zostera / django-modeltrans Goto Github PK
View Code? Open in Web Editor NEWTranslate Django model fields in a PostgreSQL JSONField
Home Page: http://django-modeltrans.readthedocs.io/en/latest/
License: BSD 3-Clause "New" or "Revised" License
Translate Django model fields in a PostgreSQL JSONField
Home Page: http://django-modeltrans.readthedocs.io/en/latest/
License: BSD 3-Clause "New" or "Revised" License
In order to add translations to a field in a Model, If I create the Model class, make the migrations to DB and then I add the i18n field, it works OK
but
If I create the model class with the i18n field directly it fails when I apply the migrations.
Something like this:
class Migration(migrations.Migration):
# ...
operations = [
migrations.RunSQL(
[("CREATE INDEX attrs_attribute_i18n_gin ON %s USING gin"
"(i18n jsonb_path_ops);", [AsIs(Product._meta.db_table)])],
[('DROP INDEX attrs_attribute_i18n_gin;', None)],
)
]
current generated query:
SELECT
"projects_project"."name",
"projects_project"."i18n",
COALESCE(("projects_project"."i18n"->>'name_nl'), "projects_project"."name") AS "name_i18n_annotation"
FROM "projects_project"
LEFT OUTER JOIN "projects_project_protocols" ON ("projects_project"."id" = "projects_project_protocols"."project_id")
LEFT OUTER JOIN "projects_projectspecies" ON ("projects_project"."id" = "projects_projectspecies"."project_id")
LEFT OUTER JOIN "species_species" ON ("projects_projectspecies"."species_id" = "species_species"."id")
WHERE (
"projects_project_protocols"."protocol_id" IN (
SELECT "U0"."id" AS Col1
FROM "protocols_protocol" "U0"
WHERE UPPER(COALESCE(("protocols_protocol".i18n->>'name_nl'), "U0"."name")::text) LIKE UPPER('%vlinder%')
)
ORDER BY "projects_project"."id" ASC
The modeltrans rewrite in the subquery ("protocols_protocol"."i18n"->>'name_nl')
should be ("U0".i18n->>'name_nl')
, i.e. should use the alias for protocols_protocols
When a language with a subcode is requested, e.g. pt-BR
, and a translation is not available, we should fall back to the main language (in this example: pt
) before falling back to the fallback language.
TypeError: __str__ returned non-string (type __proxy__)
Reproduce the error:
# settings.py
USE_I18N = False
Solution:
Use gettext
inside methods of class instance, but gettext_lazy
on class fields
For example:
from django.utils.translation import gettext_lazy as _, gettext as __
...
class TranslatedVirtualField:
some_field = _('Description of field')
...
@property
def help_text(self):
if self._help_text is not None:
return self._help_text
if get_modeltrans_setting("MODELTRANS_ADD_FIELD_HELP_TEXT") and self.language is None:
return __("current language: {}").format(get_language())
def contribute_to_class(self, cls, name):
self.model = cls
self.attname = name
self.name = name
self.column = None
# Use a translated verbose name:
translated_field_name = __(self.original_field.verbose_name)
...
LANGUAGE_OPTIONS = ["all", "browser", "fallback"]
"all" option is added so the user can add all system language in one go.
def build_localized_fieldname(field_name, lang):
if lang == "id":
# The 2-letter Indonesian language code is problematic with the
# current naming scheme as Django foreign keys also add "id" suffix.
lang = "ind"
return str("{}_{}".format(field_name, lang.replace("-", "_")))
I find this a bit odd. As an example, I have pt-br
and fields are stored as name_pt_br
. This is harder to reverse.
I'm pretty sure you have a reason to do it, my question goal is to understand the reason.
Thanks
Hi. Are related field lookups supported? If not, is there a plan to do so?
Sample:
This is not working:
listings = Listing.objects.filter(categories__slug_i18n__in=value)
Exception:
File "/Users/erik/env/ultralist-tenant/lib/python3.7/site-packages/django/db/backends/postgresql/operations.py", line 105, in quote_name
if name.startswith('"') and name.endswith('"'):
AttributeError: 'NoneType' object has no attribute 'startswith'
Current workaround:
categories = Category.objects.filter(slug_i18n__in=value)
listings = Listing.objects.filter(categories__in=categories)
Thanks a lot.
Rewrite fieldnames in F
expressions
https://github.com/deschler/django-modeltranslation/blob/master/modeltranslation/manager.py#L314
Hi there. Any ideas how to apply ActiveLanguageMixin of the InlineModelAdmin please?
Currently, having a lookup like foo__bar
will result in an exception being raised.
FieldError: Field (foo_) is not defined as translatable
This also needs some tests with common field names (in which probably will miss quite some edge cases early on)
Assume you have the settings
LANGUAGE_CODE = "en"
MODELTRANS_FALLBACK = {"default": ("de",)},
and the following model instance:
blog = Blog.objects.create(title="foo")
The following example shows that the fallback behavior of TranslatedVirtualField.__get__()
and TranslatedVirtualField.as_expression()
is different, which is in my opinion not intuitive:
>>> with override("de"): print(blog.title_i18n)
foo
>>> with override("de"): print(Blog.objects.filter(id=blog.id).values("title_i18n"))
<MultilingualQuerySet [{'title_i18n': None}]>
This is because __get__()
falls back to the original field value, whereas as_expression()
only considers the languages in the fallback chain but not the original field value.
Adding the following before the Coalesce
in as_expression()
would fix that:
lookups.append(bare_lookup.replace(self.name, self.original_name))
This would, in addition, also fix the error that you get in as_expression()
when you specify an empty fallback chain by MODELTRANS_FALLBACK = {"default": ()}
:
ValueError: Coalesce must take at least two expressions
django-modeltrans/modeltrans/migration.py
Line 131 in fe8429d
This:
attrs = Attribute.objects.filter(observationattr__object_id__in=observation_ids) \
.values('name_i18n', 'unit__symbol')
fails in modeltrans/manager.py
on line 152 while it tries to model._meta.get_field()
:
Attribute has no field named 'observationattr__object_id'
could be just another management command creating/removing the correct GIN index
Hi. I'd like to ask for help how to safely change LANGUAGE_CODE in the settings.
I started project with default language "sk" and created around 500 translations into language "en" across whole database in different models. Later I realised it would be better to have "en" as a default language, so I changed the settings.LANGUAGE_CODE to "en". The issue is, the translations are still saved in regular table column in language "sk" and i18n column contains "en" translations. If I understand it correctly, it needs to be switched. Can anybody guide me how to do it safely without losing translated data, please?
Thank you very much.
Lookups are tranformed when the queryset definition is executed, which might be unexpected behavior with querysets.
An problematic use case might be defining the choices for a ModelChoiceField
.
from django.utils.translation import override
with override('en'):
qs = Blog.objects.filter(title_i18n='foo')
print(str(qs.query))
# SELECT "app_blog"."id", "app_blog"."title", "app_blog"."body", "app_blog"."category_id", "app_blog"."i18n"
# FROM "app_blog"
# WHERE "app_blog"."title" = 'foo'
with override('nl'):
print(str(qs.query))
# same query
with override('nl'):
qs = Blog.objects.filter(title_i18n='foo')
print(str(qs.query))
# SELECT "app_blog"."id", "app_blog"."title", "app_blog"."body", "app_blog"."category_id", "app_blog"."i18n", COALESCE(("app_blog"."i18n" ->> 'title_nl'), "app_blog"."title") AS "title_i18n_annotation"
# FROM "app_blog"
# WHERE COALESCE(("app_blog"."i18n" ->> 'title_nl'), "app_blog"."title") = 'foo'
Using a callable helps, but I'm not sure if the queryset
argument of ModelChoiceField supports that:
qs = lambda: Blog.objects.filter(title_i18n='foo')
with override('nl'):
print(str(qs().query))
# SELECT "app_blog"."id", "app_blog"."title", "app_blog"."body", "app_blog"."category_id", "app_blog"."i18n", COALESCE(("app_blog"."i18n" ->> 'title_nl'), "app_blog"."title") AS "title_i18n_annotation"
# FROM "app_blog"
# WHERE COALESCE(("app_blog"."i18n" ->> 'title_nl'), "app_blog"."title") = 'foo'
with override('en'):
print(str(qs().query))
# SELECT "app_blog"."id", "app_blog"."title", "app_blog"."body", "app_blog"."category_id", "app_blog"."i18n"
# FROM "app_blog"
# WHERE "app_blog"."title" = 'foo'
At the moment labels of fields are hard coded to include the language code and translation / default language in brackets. By including a customizable translatable string in Meta options this can become customizable.
Hello:
def _filter_or_exclude(self, negate, args, kwargs)
sometimes generates None query which causes TypeError. Any ideas why and how to fix it please?
Traceback (most recent call last):
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/options.py", line 616, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/options.py", line 1697, in changelist_view
cl = self.get_changelist_instance(request)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/options.py", line 736, in get_changelist_instance
return ChangeList(
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/views/main.py", line 99, in __init__
self.queryset = self.get_queryset(request)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/contrib/admin/views/main.py", line 488, in get_queryset
qs = self.root_queryset.filter(Exists(qs))
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/query.py", line 941, in filter
return self._filter_or_exclude(False, args, kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/modeltrans/manager.py", line 300, in _filter_or_exclude
return super()._filter_or_exclude(negate, new_args, new_kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/query.py", line 961, in _filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/query.py", line 968, in _filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1393, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1412, in _add_q
child_clause, needed_inner = self.build_filter(
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1265, in build_filter
return self._add_q(
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1412, in _add_q
child_clause, needed_inner = self.build_filter(
File "/Users/erik/env/eskills/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1283, in build_filter
arg, value = filter_expr
TypeError: cannot unpack non-iterable NoneType object
Output of negate, new_args and new_kwargs in modeltrans.manager._filter_or_exclude
:
False [] {'sites__id__exact': '1'}
False [] {}
False [] {}
False [] {'pk': OuterRef(pk)}
False [<Q: (AND: None)>] {}
Running the tests with django==4.2
reveals a test failure:
new_args = [Q(self._rewrite_Q(arg)) for arg in args if arg]
File "/home/runner/work/django-modeltrans/django-modeltrans/modeltrans/manager.py", line 196, in _rewrite_Q
return Q._new_instance(
AttributeError: type object 'Q' has no attribute '_new_instance'
django/django#14677 seems to be related.
values()
values_list()
defer()
/only()
-related things.Appending the language is not lazy, so it results in the english translation being used.
django-modeltrans/modeltrans/fields.py
Line 89 in 1796704
I was profiling import time in a project using django-modeltrans after reading https://adamj.eu/tech/2023/03/02/django-profile-and-improve-import-time/, while I noticed the time it takes to import a forms module containing a form based on TranslationModelForm
is somewhat excessive, replacing the use of TranslationModelForm
by ModelForm
reduced the import time by a factor 3.
Proper sphinx docs for django-modeltrans.
Seems we inadvertently migrated a setting from django-modeltranslation
. Best to use either a MODELTRANS
settings dict, or all MODELTRANS_*
settings.
If the i18n
field is deferred, i18n
is just an empty dict, so getting a translated value will always return the default language:
from django.utils.translation import override
from app.models import Blog
with override('nl'):
print "\nWith defer('i18n'):"
print ' ' + ', '.join([b.title_i18n for b in Blog.objects.all().defer('i18n')])
print "\nWithout defer('i18n'):"
print ' ' + ', '.join([b.title_i18n for b in Blog.objects.all()])
result.
With defer('i18n'):
Falcon, Frog, Toad, Duck, Dragonfly, Crayfish, Cod, Dolphin
Without defer('i18n'):
Valk, Kikker, Pad, Eend, Libellen, Crayfish, Cod, Dolfijn
I think this is more or less ok, but needs to be documented.
Alternatively,
i18n
is deferred. I think this is undesirable.i18n
deferred. This would warn the user if he doesn't know what he is doing, but still allow deferring i18n
. I propose doing this if we get feedback that current behaviour is not clear.If ordering
is defined in Model.Meta
, the values doesn't pass through the standard queryset interface and probably doesn't allow using the <field>_i18n
version of the field, which does make a lot of sense while ordering translated data.
Example:
from django.db import models
from modeltrans.fields import TranslationField
class Blog(models.Model):
name = models.CharField(max_length=100)
body = models.TextField()
i18n = TranslationField(fields=('name', 'body'))
class Meta:
ordering = ('name', )
Currently, django-modeltrans shows all languages when using the change view in the django admin. More than a couple of languages will give too much clutter, so it would be nice to be able to show only the base language and the currently active language by adding a mixin to the model admin class.
It will be quite hard to test, as it involves some manual steps, but parts of it can be tested
copy_translations
method.Maybe generating the manual part of transforming the translation.py
s is a good step towards better test-ability.
django.contrib.postgres.fields.JSONField is deprecated and generates warnings in Django>=3.1
Example:
Using protocols.Choice.i18n: (fields.W904) django.contrib.postgres.fields.JSONField is deprecated. Support for it (except in historical migrations) will be removed in Django 4.0.
HINT: Use django.db.models.JSONField instead.
Solution:
Use django.db.models.JSONField
requires stable and unique names for annotations.
Consider removing registration.
Defining the modal as translatable by:
TranslationJSONField
to the model, define the translatable fields with an argument to this columns contructor.contribute_to_class
to inject the proper manager.Currently, everything is cast to TextField
while making annotations and the virtual fields are subclasses of CharField
the LIKE '%or%'
is added twice:
SELECT DISTINCT "projects_project"."id",
"projects_project"."name",
"projects_project"."description",
"projects_project"."group_id",
"projects_project"."created",
"projects_project"."updated",
"projects_project"."i18n",
COALESCE(("projects_project"."i18n" ->> 'name_nl'), "projects_project"."name") AS "name_i18n_annotation",
"species_species"."name"::varchar(100) AS "species__name_related_helper"
FROM "projects_project"
LEFT OUTER JOIN "projects_projectspecies" ON ("projects_project"."id" = "projects_projectspecies"."project_id")
LEFT OUTER JOIN "species_species" ON ("projects_projectspecies"."species_id" = "species_species"."id")
LEFT OUTER JOIN "projects_project_protocols" ON ("projects_project"."id" = "projects_project_protocols"."project_id")
WHERE
("projects_project_protocols"."protocol_id" IN (
SELECT U0."id" AS Col1
FROM "protocols_protocol" U0
WHERE UPPER(COALESCE((U0."i18n" ->> 'name_nl'), U0."name")::text) LIKE UPPER('%or%')
) OR
UPPER(COALESCE(("species_species"."i18n" ->> 'name_nl'), "species_species"."name")::text) LIKE UPPER('%or%') OR
UPPER(COALESCE(("species_species"."i18n" ->> 'name_nl'), "species_species"."name")::text) LIKE UPPER('%or%'))
ORDER BY "name_i18n_annotation" ASC LIMIT 25
First of all I appreciate to make this lovely library.
Here is my question.
In default settings, I can see all translated fields.
But when I assign fields
in ModelAdmin like this.
class ProgramAdmin(admin.ModelAdmin):
model = Program
fields = ('title', ...)
Then, just one field displayed like below.
@pjburon This clearly is a different issue, so created a new one.
originally reported in #34
This Queryset
Blog.objects.filter(
Q(category__slug_i18n=slug) | Q(category__parent__slug_i18n=slug),
is_active=active
)
Results for language = en
in:
result: <MultilingualQuerySet [<Blog: Duck>, <Blog: Falcon>]>
SELECT ...
FROM "app_blog"
INNER JOIN "app_category" ON ("app_blog"."category_id" = "app_category"."id")
LEFT OUTER JOIN "app_category" T3 ON ("app_category"."parent_id" = T3."id")
WHERE (("app_category"."slug" = 'birds'
OR T3."slug" = 'birds')
AND "app_blog"."is_active" = true)
and for language = en
in:
result: <MultilingualQuerySet []>
SELECT ..., "app_blog"."i18n", COALESCE((T3."i18n" ->> 'slug_nl'), T3."slug") AS "slug_i18n_annotation"
FROM "app_blog"
LEFT OUTER JOIN "app_category" ON ("app_blog"."category_id" = "app_category"."id")
LEFT OUTER JOIN "app_category" T3 ON ("app_category"."parent_id" = T3."id")
WHERE ((COALESCE((T3."i18n" ->> 'slug_nl'), T3."slug") = 'birds'
OR COALESCE((T3."i18n" ->> 'slug_nl'), T3."slug") = 'birds')
AND "app_blog"."is_active" = true)
So the problem is the duplicated LEFT OUTER JOIN
.
Maybe use a different data structure in the data migration. The current structure still requires parsing (using split_translated_filename
):
todo = (
('Unit', ('name_ka', 'name_nl', 'name_en')),
('Attribute', ('name_en', 'name_nl', 'name_ka')),
('Choice', ('name_ka', 'name_nl', 'name_en', 'description_ka', 'description_nl', 'description_en')),
)
We could also use something like this:
todo = (
('Unit', (('name', ('ka', 'nl', 'en')))),
('Attribute', (('name', ('ka', 'nl', 'en')))),
('Choice', (('name', ('ka', 'nl', 'en'))), ('description', ('ka', 'nl', 'en')))),
)
or even
todo = {
'Unit': {
'name': ('ka', 'nl', 'en'),
},
'Attribute': {
'name': ('ka', 'nl', 'en'),
},
'Choice': {
'name': ('ka', 'nl', 'en'),
'description': ('ka', 'nl', 'en'),
}
}
Idea is to add fallback_readonly
option to Meta options and kwargs so that any form fields of the fallback language are set to read only. This is useful if translators are not allowed to alter the original fallback text.
Currently, if I add description_i18n
instead of description
to the fieldlist in ModelForm.Meta.fields
, I get this error:
django.core.exceptions.FieldError: 'description_i18n' cannot be specified for Project model form as it is a non-editable field
It should be possible to add the translated field to a ModelForm
.
Blog.objects.filter(category__name_nl='Vogels')
for a model, if the title is translatable, then use json type for title field, and save title like:
{'en': 'english title', 'fr':'titre français'}
similar to the package for laravel: https://github.com/spatie/laravel-translatable
Traceback looks like this:
Traceback (most recent call last):
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/core/paginator.py", line 85, in count
return self.object_list.count()
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/query.py", line 387, in count
print(repr(self))
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/query.py", line 248, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/query.py", line 272, in __iter__
self._fetch_all()
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/query.py", line 1180, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1055, in execute_sql
sql, params = self.as_sql()
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 461, in as_sql
where, w_params = self.compile(self.where) if self.where is not None else ("", [])
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 393, in compile
sql, params = node.as_sql(self, self.connection)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/where.py", line 80, in as_sql
sql, params = compiler.compile(child)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 393, in compile
sql, params = node.as_sql(self, self.connection)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/where.py", line 80, in as_sql
sql, params = compiler.compile(child)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 393, in compile
sql, params = node.as_sql(self, self.connection)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/lookups.py", line 160, in as_sql
lhs_sql, params = self.process_lhs(compiler, connection)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/lookups.py", line 151, in process_lhs
lhs_sql, params = super().process_lhs(compiler, connection, lhs)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/lookups.py", line 78, in process_lhs
return compiler.compile(lhs)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 393, in compile
sql, params = node.as_sql(self, self.connection)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/expressions.py", line 743, in as_sql
return "%s.%s" % (qn(self.alias), qn(self.target.column)), []
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 384, in quote_name_unless_alias
r = self.connection.ops.quote_name(name)
File "/Users/jieter/.virtualenvs/meetnetten/lib/python3.6/site-packages/django/db/backends/postgresql/operations.py", line 98, in quote_name
if name.startswith('"') and name.endswith('"'):
AttributeError: 'NoneType' object has no attribute 'startswith'
When doing something like Category.objects.filter(blog__title_i18n__icontains='django')
with these models:
class Category(models.Model):
title = models.CharField(max_length=255)
class Blog(models.Model):
title = models.CharField(max_length=255)
body = models.TextField(null=True)
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.CASCADE)
i18n = TranslationField(fields=("title", "body"))
It would be nice if you could provide a friendly message.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.