-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unable to Make existing fields translatable #263
Comments
Just now I noticed that my projects migrations were apparently completely destroyed by "parler". I tried to go back on my changes and now I am completely stuck on a non existing migration. This thing is pretty much a disaster. |
@HappyMiner please use latest django-parler>=2.0.1. In addition you need to set Consider e.g. a file migrations.CreateModel(
name='AttachmentType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'verbose_name': 'Attachment type',
'verbose_name_plural': 'Attachment types',
},
bases=(parler.models.TranslatableModelMixin, models.Model),
),
migrations.CreateModel(
name='AttachmentTypeTranslation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')),
('name', models.CharField(max_length=500, unique=True, verbose_name='Name')),
('master', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='jobportal.AttachmentType')),
],
options={
'verbose_name': 'Attachment type Translation',
'db_table': 'jobportal_attachmenttype_translation',
'db_tablespace': '',
'managed': True,
'default_permissions': (),
},
bases=(parler.models.TranslatedFieldsModelMixin, models.Model),
), In particular if you changed your model e.g.
and
The documentation lacks for this information. Feel free to contact me if you have any further questions. |
@vdboor perhaps add some documentation in https://django-parler.readthedocs.io/en/stable/advanced/migrating.html about this issue to clarify things. Cause this issue pops up regulary. |
I had the same problem and i had change the migrations field of the translation |
Upgrade your django-parler to the latest version by: |
(venv) D:\html\nd\myshop>python manage.py makemigrations shop --name "translations" |
Looks like the documentation is talking about some future dream. The code explicitly mentions in comments that it isn't supported to change an existing field into a translated field. |
Changing an existing non-translated field to a translated one requires a multi-step process. The translated fields are first created with a different temporary name. Then data is copied from the non-translated fields to the translated fields. The old fields are removed and the translated fields are renamed to have the same name as the original fields had. All this resides in the single migration file in this commit. A few changes were required to an old migration file. 1) The bases needs to include TranslatableModelMixin in the migration where LoginMethod model is first introduced. This is required by Django-parler and how it works internally. django-parler/django-parler#263 (comment) 2) The non-null `name` field requires a default value so that migrating backwards works. The backward migration creates the non-null `name` column which fails unless the column also has a default value.
Changing an existing non-translated field to a translated one requires a multi-step process. The translated fields are first created with a different temporary name. Then data is copied from the non-translated fields to the translated fields. The old fields are removed and the translated fields are renamed to have the same name as the original fields had. All this resides in the single migration file in this commit. A few changes were required to an old migration file. 1) The bases needs to include TranslatableModelMixin in the migration where LoginMethod model is first introduced. This is required by Django-parler and how it works internally. django-parler/django-parler#263 (comment) 2) The non-null `name` field requires a default value so that migrating backwards works. The backward migration creates the non-null `name` column which fails unless the column also has a default value.
I also ran into problems with making existing fields translatable. But I succeeded, having tried a lot. As I won't be alone, my story so far. I'm on Django 4.0.4 with django-parler 2.3 with a very basic class: class Plan(models.Model):
title = models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=_('Price per year')) The table does contain data. I've followed the documentation at migration. So I changed my class to: class Plan(TranslatableModel):
title = models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True)
translations = TranslatedFields(
title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=_('Price per year')) At first I got the error **TypeError: Translatable model <class 'fake.Plan'> does not appear to inherit from TranslatableModel I fixed that by following some suggestion here. Just added to the migration file
But then I got the error TypeError: The model 'Plan' already has a field named 'title' I suspected the migration system to be the culprit here as the second title attribute should be part of PlanTranslation, not of Plan. I changed the name of the attribute to the_title: class Plan(TranslatableModel):
title = models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True)
translations = TranslatedFields(
the_title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=_('Price per year')) Ran makemigrations again and then edited the migration file to rename the_title to title again before running the actual migration. The migration system didn't like that. Deleted the migration, and edited the model to: class Plan(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=_('Price per year')) Created the migration file and edited. Removed the RemoveField part and tried to run the migration. The migration system didn't like that either. So, back to the the_title version with: class Plan(TranslatableModel):
title = models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True)
translations = TranslatedFields(
the_title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
)
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=_('Price per year')) Created the migration with makemigrations and ran it with migrate. No issues here. Then created an empty migration to rename the_title to title in PlanTranslation:
Before running th emigration, I included an operation into this migration file: migrations.RenameField(
model_name = 'PlanTranslation',
old_name = 'the_title',
new_name = 'title',
), The migration system sure isn't stupid. It didn't buy this and complained with TypeError: The model 'Plan' already has a field named 'title' Deleted the migration file and added another empty migration file as per the instructions
Inserted the functions into the empty migration. I modified the forwards_func and backwards_func to reflect the proper model names and proper field names. Note: I do have both the attributes title and the_title. ...
def forwards_func(apps, schema_editor):
MyModel = apps.get_model('myapp', 'Plan')
MyModelTranslation = apps.get_model('myapp', 'PlanTranslation')
for object in MyModel.objects.all():
MyModelTranslation.objects.create(
master_id=object.pk,
language_code=settings.LANGUAGE_CODE,
the_title=object.title
)
def backwards_func(apps, schema_editor):
MyModel = apps.get_model('myapp', 'Plan')
MyModelTranslation = apps.get_model('myapp', 'PlanTranslation')
for object in MyModel.objects.all():
translation = _get_translation(object, MyModelTranslation)
object.title = translation.the_title
object.save() # Note this only calls Model.save()
... And inserted the code to run the functions into the operations list: operations = [
migrations.RunPython(forwards_func, backwards_func),
] Then I ran the migration with
Verified if the data got copied to the PlanTranslation table. It was. Now I needed to have the_title renamed to title and get rid of the title field in Plan. Just rename the title field in the model first and run migrations: class Plan(TranslatableModel):
old_title = models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True)
translations = TranslatedFields(
the_title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
) Edit the models again, rename the_title to title and remove the attribute old_title and run migrations: class Plan(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=40, unique=True, verbose_name=_('Name'), db_index=True),
) This worked for me. I have the system up & running now. Edited the admin.py as per the documentation and it sure looks great in the admin. Tested the functionality and database contents: everything ok. |
I came to this solution in my: This was the migration generated by django:
Then I edited to do a data migration:
I put the deletes to be done after creating the translation table and before deleting I copied the data with: migrations.RunSQL("INSERT INTO (language_code, <Yours_parameters>, master_id) SELECT '<your_language>' , <Yours_parameters>, id FROM ;"), |
Hello,
I think I just found a problem in the documentation at: https://django-parler.readthedocs.io
I am trying to translate my model fields and when I try to follow the procedure described in the docs, all I get is:
raise TypeError("Translatable model {} does not appear to inherit from TranslatableModel".format(shared_model)) TypeError: Translatable model <class '__fake__.Product'> does not appear to inherit from TranslatableModel
When I try to follow the docs, Python complains that the fields that are in
translations = TranslatedFields
are duplicated, so the first part of the doc does not work. No idea how to continue at this point, as this is complete road block for me.Please find below the relevant data classes where I attempt to perform the translations.
Related admin classes:
The text was updated successfully, but these errors were encountered: