Git Product home page Git Product logo

django-modeltrans's People

Contributors

atugushev avatar browniebroke avatar bulatshafigullin avatar danielvdp avatar dependabot[bot] avatar dfirst avatar dyve avatar jieter avatar zvolsky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

django-modeltrans's Issues

Right order to create translations

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.

Create index in datamigration

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)],
        )
    ]

Rewriting should use alias when used in subquery

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

Fallback to default language when subcodes are used

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__)

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)

...

Use django.db.models.fields.json.KeyTransform

Use django.db.models.fields.json.KeyTransform instead of django.contrib.postgres.fields.jsonb.KeyTransform - doc.

I think that when solving this issue, the #76 issue will be solved automatically. At least for me since I am using sqlite for tests.

Why change dash to underscore on the language part?

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

Related lookups

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.

Improve robustness of check if a field is a translated field

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)

Fallback behavior of virtual fields inconsistent with behavior when used in expressions

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

Enhance decomposing the lookup in manager methods

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'

How to change default LANGUAGE_CODE

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.

non-lazyness of the <field>_i18n lookup transformation

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'

TypeError: cannot unpack non-iterable NoneType object

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)>] {}

Support for django 4.2

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.

Documentation

Proper sphinx docs for django-modeltrans.

  • Proper sphinx config
  • explanation of inner workings
  • API documentation
  • brief listing of alternative solutions
  • migrating from django-modeltranslation.
  • Deploy to readthedocs.org

What to do when user uses `defer('i18n')`

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,

  • we could raise an error if i18n is deferred. I think this is undesirable.
  • we could raise a warning if 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.

support translated/_i18n fields in model.Meta.ordering

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', )

Admin mixin to hide certain languages in the change view

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.

Test for migration path from django-modeltranslation

It will be quite hard to test, as it involves some manual steps, but parts of it can be tested

  • Unit tests for the copy_translations method.
  • A test running on an example project with the manually created migrations

Maybe generating the manual part of transforming the translation.pys is a good step towards better test-ability.

Use django.db.models.JSONField

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

Consider removing registration

Consider removing registration.

Defining the modal as translatable by:

  1. adding the TranslationJSONField to the model, define the translatable fields with an argument to this columns contructor.
  2. using this JSON column's contribute_to_class to inject the proper manager.

Mix the original field with VirtualTranslationField

Currently, everything is cast to TextField while making annotations and the virtual fields are subclasses of CharField

  • Use the original field to inherit from in a factory function.
  • Cast to the original field while making annotations
  • tests.

double filter on same field

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

Could not displayed translated fields when I assign `fields` in ModelAdmin

First of all I appreciate to make this lovely library.

Here is my question.

In default settings, I can see all translated fields.

2018-03-26 15 42 22

But when I assign fields in ModelAdmin like this.

class ProgramAdmin(admin.ModelAdmin):
    model = Program

    fields = ('title', ...)

Then, just one field displayed like below.

2018-03-26 15 43 47

Duplicated LEFT OUTER JOIN with two related lookups on translated fields

@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.

Data structure defining what to copy in the data migration

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'),
    }
}

Allow use of <field>_i18n in ModelForm

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.

Error message from query made from model without MultilingualManager is vague.

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.