mirror of
https://github.com/inventree/InvenTree.git
synced 2026-04-04 18:40:55 +00:00
Overhaul of migration strategy
- New models simply point to the old database tables - Perform schema and data migrations on the old models first (in the part app) - Swap model references in correct order
This commit is contained in:
@@ -1,256 +0,0 @@
|
|||||||
# Generated by Django 5.2.8 on 2025-12-03 11:51
|
|
||||||
|
|
||||||
import InvenTree.models
|
|
||||||
import InvenTree.validators
|
|
||||||
from django.conf import settings
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
"""Create new ParameterTemplate and Parameter models.
|
|
||||||
|
|
||||||
Ref: https://github.com/inventree/InvenTree/pull/10699
|
|
||||||
|
|
||||||
These models have been migrated from the following (existing) models:
|
|
||||||
- part.PartParameterTemplate -> common.ParameterTemplate
|
|
||||||
- part.PartParameter -> common.Parameter
|
|
||||||
|
|
||||||
To preserve the existing data, we will use the existing database tables.
|
|
||||||
|
|
||||||
For this to work, the existing models (part.PartParameterTemplate and part.PartParameter)
|
|
||||||
must have already had schema and migrations applied:
|
|
||||||
|
|
||||||
- part/migrations/0144_auto_20251203_1045.py
|
|
||||||
- part/migrations/0145_auto_20251203_1120.py
|
|
||||||
"""
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0039_emailthread_emailmessage"),
|
|
||||||
("part", "0145_auto_20251203_1120"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="ParameterTemplate",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.AutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"metadata",
|
|
||||||
models.JSONField(
|
|
||||||
blank=True,
|
|
||||||
help_text="JSON metadata field, for use by external plugins",
|
|
||||||
null=True,
|
|
||||||
verbose_name="Plugin Metadata",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"model_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True, null=True,
|
|
||||||
help_text="Target model type for this parameter template",
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
to="contenttypes.contenttype",
|
|
||||||
verbose_name="Model type",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"name",
|
|
||||||
models.CharField(
|
|
||||||
help_text="Parameter Name",
|
|
||||||
max_length=100,
|
|
||||||
unique=True,
|
|
||||||
verbose_name="Name",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"units",
|
|
||||||
models.CharField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Physical units for this parameter",
|
|
||||||
max_length=25,
|
|
||||||
validators=[InvenTree.validators.validate_physical_units],
|
|
||||||
verbose_name="Units",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"description",
|
|
||||||
models.CharField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Parameter description",
|
|
||||||
max_length=250,
|
|
||||||
verbose_name="Description",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"checkbox",
|
|
||||||
models.BooleanField(
|
|
||||||
default=False,
|
|
||||||
help_text="Is this parameter a checkbox?",
|
|
||||||
verbose_name="Checkbox",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"choices",
|
|
||||||
models.CharField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Valid choices for this parameter (comma-separated)",
|
|
||||||
max_length=5000,
|
|
||||||
verbose_name="Choices",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"selectionlist",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
help_text="Selection list for this parameter",
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
related_name="templates",
|
|
||||||
to="common.selectionlist",
|
|
||||||
verbose_name="Selection List",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"enabled",
|
|
||||||
models.BooleanField(
|
|
||||||
default=True,
|
|
||||||
help_text="Is this parameter template enabled?",
|
|
||||||
verbose_name="Enabled",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "Parameter Template",
|
|
||||||
"verbose_name_plural": "Parameter Templates",
|
|
||||||
"db_table": "part_partparametertemplate",
|
|
||||||
"managed": False,
|
|
||||||
},
|
|
||||||
bases=(InvenTree.models.PluginValidationMixin, models.Model),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="Parameter",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.AutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"metadata",
|
|
||||||
models.JSONField(
|
|
||||||
blank=True,
|
|
||||||
help_text="JSON metadata field, for use by external plugins",
|
|
||||||
null=True,
|
|
||||||
verbose_name="Plugin Metadata",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"updated",
|
|
||||||
models.DateTimeField(
|
|
||||||
blank=True,
|
|
||||||
default=None,
|
|
||||||
help_text="Timestamp of last update",
|
|
||||||
null=True,
|
|
||||||
verbose_name="Updated",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"model_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
to="contenttypes.contenttype",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"model_id",
|
|
||||||
models.PositiveIntegerField(
|
|
||||||
help_text="ID of the target model for this parameter",
|
|
||||||
verbose_name="Model ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"data",
|
|
||||||
models.CharField(
|
|
||||||
help_text="Parameter Value",
|
|
||||||
max_length=500,
|
|
||||||
validators=[django.core.validators.MinLengthValidator(1)],
|
|
||||||
verbose_name="Data",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"data_numeric",
|
|
||||||
models.FloatField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"note",
|
|
||||||
models.CharField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Optional note field",
|
|
||||||
max_length=500,
|
|
||||||
verbose_name="Note",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"template",
|
|
||||||
models.ForeignKey(
|
|
||||||
help_text="Parameter template",
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="parameters",
|
|
||||||
to="common.parametertemplate",
|
|
||||||
verbose_name="Template",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"updated_by",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
help_text="User who last updated this object",
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
related_name="%(class)s_updated",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
verbose_name="Update By",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
"verbose_name": "Parameter",
|
|
||||||
"verbose_name_plural": "Parameters",
|
|
||||||
"unique_together": {("model_type", "model_id", "template")},
|
|
||||||
"db_table": "part_partparameter",
|
|
||||||
"managed": False,
|
|
||||||
},
|
|
||||||
bases=(InvenTree.models.PluginValidationMixin, models.Model),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name="parameter",
|
|
||||||
index=models.Index(
|
|
||||||
fields=["model_type", "model_id"], name="common_para_model_t_244405_idx"
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="parameter",
|
|
||||||
options={"verbose_name": "Parameter", "verbose_name_plural": "Parameters"},
|
|
||||||
),
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name="parametertemplate",
|
|
||||||
options={
|
|
||||||
"verbose_name": "Parameter Template",
|
|
||||||
"verbose_name_plural": "Parameter Templates",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,226 +1,248 @@
|
|||||||
# Generated by Django 4.2.25 on 2025-11-10 10:51
|
# Generated by Django 5.2.8 on 2025-12-03 12:39
|
||||||
|
|
||||||
import InvenTree.models
|
import InvenTree.models
|
||||||
import InvenTree.validators
|
import InvenTree.validators
|
||||||
from django.conf import settings
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
("common", "0039_emailthread_emailmessage"),
|
("common", "0039_emailthread_emailmessage"),
|
||||||
("part", "0143_alter_part_image")
|
("contenttypes", "0002_remove_content_type_name"),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
("part", "0144_auto_20251203_1045")
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.SeparateDatabaseAndState(
|
||||||
name="ParameterTemplate",
|
state_operations=[
|
||||||
fields=[
|
migrations.CreateModel(
|
||||||
(
|
name="ParameterTemplate",
|
||||||
"id",
|
fields=[
|
||||||
models.AutoField(
|
(
|
||||||
auto_created=True,
|
"id",
|
||||||
primary_key=True,
|
models.AutoField(
|
||||||
serialize=False,
|
auto_created=True,
|
||||||
verbose_name="ID",
|
primary_key=True,
|
||||||
),
|
serialize=False,
|
||||||
),
|
verbose_name="ID",
|
||||||
(
|
),
|
||||||
"metadata",
|
),
|
||||||
models.JSONField(
|
(
|
||||||
blank=True,
|
"metadata",
|
||||||
help_text="JSON metadata field, for use by external plugins",
|
models.JSONField(
|
||||||
null=True,
|
blank=True,
|
||||||
verbose_name="Plugin Metadata",
|
help_text="JSON metadata field, for use by external plugins",
|
||||||
),
|
null=True,
|
||||||
),
|
verbose_name="Plugin Metadata",
|
||||||
(
|
),
|
||||||
"model_type",
|
),
|
||||||
models.ForeignKey(
|
(
|
||||||
blank=True, null=True,
|
"name",
|
||||||
help_text="Target model type for this parameter template",
|
models.CharField(
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
help_text="Parameter Name",
|
||||||
to="contenttypes.contenttype",
|
max_length=100,
|
||||||
verbose_name="Model type",
|
unique=True,
|
||||||
),
|
verbose_name="Name",
|
||||||
),
|
),
|
||||||
(
|
),
|
||||||
"name",
|
(
|
||||||
models.CharField(
|
"units",
|
||||||
help_text="Parameter Name",
|
models.CharField(
|
||||||
max_length=100,
|
blank=True,
|
||||||
unique=True,
|
help_text="Physical units for this parameter",
|
||||||
verbose_name="Name",
|
max_length=25,
|
||||||
),
|
validators=[InvenTree.validators.validate_physical_units],
|
||||||
),
|
verbose_name="Units",
|
||||||
(
|
),
|
||||||
"units",
|
),
|
||||||
models.CharField(
|
(
|
||||||
blank=True,
|
"description",
|
||||||
help_text="Physical units for this parameter",
|
models.CharField(
|
||||||
max_length=25,
|
blank=True,
|
||||||
validators=[InvenTree.validators.validate_physical_units],
|
help_text="Parameter description",
|
||||||
verbose_name="Units",
|
max_length=250,
|
||||||
),
|
verbose_name="Description",
|
||||||
),
|
),
|
||||||
(
|
),
|
||||||
"description",
|
(
|
||||||
models.CharField(
|
"checkbox",
|
||||||
blank=True,
|
models.BooleanField(
|
||||||
help_text="Parameter description",
|
default=False,
|
||||||
max_length=250,
|
help_text="Is this parameter a checkbox?",
|
||||||
verbose_name="Description",
|
verbose_name="Checkbox",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"checkbox",
|
"choices",
|
||||||
models.BooleanField(
|
models.CharField(
|
||||||
default=False,
|
blank=True,
|
||||||
help_text="Is this parameter a checkbox?",
|
help_text="Valid choices for this parameter (comma-separated)",
|
||||||
verbose_name="Checkbox",
|
max_length=5000,
|
||||||
),
|
verbose_name="Choices",
|
||||||
),
|
),
|
||||||
(
|
),
|
||||||
"choices",
|
(
|
||||||
models.CharField(
|
"enabled",
|
||||||
blank=True,
|
models.BooleanField(
|
||||||
help_text="Valid choices for this parameter (comma-separated)",
|
default=True,
|
||||||
max_length=5000,
|
help_text="Is this parameter template enabled?",
|
||||||
verbose_name="Choices",
|
verbose_name="Enabled",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"selectionlist",
|
"model_type",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Selection list for this parameter",
|
help_text="Target model type for this parameter template",
|
||||||
null=True,
|
null=True,
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
related_name="templates",
|
to="contenttypes.contenttype",
|
||||||
to="common.selectionlist",
|
verbose_name="Model type",
|
||||||
verbose_name="Selection List",
|
),
|
||||||
),
|
),
|
||||||
),
|
(
|
||||||
(
|
"selectionlist",
|
||||||
"enabled",
|
models.ForeignKey(
|
||||||
models.BooleanField(
|
blank=True,
|
||||||
default=True,
|
help_text="Selection list for this parameter",
|
||||||
help_text="Is this parameter template enabled?",
|
null=True,
|
||||||
verbose_name="Enabled",
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
),
|
related_name="templates",
|
||||||
)
|
to="common.selectionlist",
|
||||||
],
|
verbose_name="Selection List",
|
||||||
options={
|
),
|
||||||
"verbose_name": "Parameter Template",
|
),
|
||||||
"verbose_name_plural": "Parameter Templates",
|
],
|
||||||
},
|
options={
|
||||||
bases=(InvenTree.models.PluginValidationMixin, models.Model),
|
"verbose_name": "Parameter Template",
|
||||||
),
|
"verbose_name_plural": "Parameter Templates",
|
||||||
migrations.CreateModel(
|
"db_table": "part_partparametertemplate",
|
||||||
name="Parameter",
|
},
|
||||||
fields=[
|
bases=(
|
||||||
(
|
InvenTree.models.ContentTypeMixin,
|
||||||
"id",
|
InvenTree.models.PluginValidationMixin,
|
||||||
models.AutoField(
|
models.Model,
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"metadata",
|
|
||||||
models.JSONField(
|
|
||||||
blank=True,
|
|
||||||
help_text="JSON metadata field, for use by external plugins",
|
|
||||||
null=True,
|
|
||||||
verbose_name="Plugin Metadata",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"updated",
|
|
||||||
models.DateTimeField(
|
|
||||||
blank=True,
|
|
||||||
default=None,
|
|
||||||
help_text="Timestamp of last update",
|
|
||||||
null=True,
|
|
||||||
verbose_name="Updated",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"model_type",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
to="contenttypes.contenttype",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"model_id",
|
|
||||||
models.PositiveIntegerField(
|
|
||||||
help_text="ID of the target model for this parameter",
|
|
||||||
verbose_name="Model ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"data",
|
|
||||||
models.CharField(
|
|
||||||
help_text="Parameter Value",
|
|
||||||
max_length=500,
|
|
||||||
validators=[django.core.validators.MinLengthValidator(1)],
|
|
||||||
verbose_name="Data",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"data_numeric",
|
|
||||||
models.FloatField(blank=True, default=None, null=True),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"note",
|
|
||||||
models.CharField(
|
|
||||||
blank=True,
|
|
||||||
help_text="Optional note field",
|
|
||||||
max_length=500,
|
|
||||||
verbose_name="Note",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"template",
|
|
||||||
models.ForeignKey(
|
|
||||||
help_text="Parameter template",
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="parameters",
|
|
||||||
to="common.parametertemplate",
|
|
||||||
verbose_name="Template",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"updated_by",
|
|
||||||
models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
help_text="User who last updated this object",
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.SET_NULL,
|
|
||||||
related_name="%(class)s_updated",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
verbose_name="Update By",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
options={
|
database_operations=[],
|
||||||
"verbose_name": "Parameter",
|
|
||||||
"verbose_name_plural": "Parameters",
|
|
||||||
"unique_together": {("model_type", "model_id", "template")},
|
|
||||||
},
|
|
||||||
bases=(InvenTree.models.PluginValidationMixin, models.Model),
|
|
||||||
),
|
),
|
||||||
migrations.AddIndex(
|
migrations.SeparateDatabaseAndState(
|
||||||
model_name="parameter",
|
state_operations=[
|
||||||
index=models.Index(
|
migrations.CreateModel(
|
||||||
fields=["model_type", "model_id"], name="common_para_model_t_244405_idx"
|
name="Parameter",
|
||||||
),
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"metadata",
|
||||||
|
models.JSONField(
|
||||||
|
blank=True,
|
||||||
|
help_text="JSON metadata field, for use by external plugins",
|
||||||
|
null=True,
|
||||||
|
verbose_name="Plugin Metadata",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"updated",
|
||||||
|
models.DateTimeField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
help_text="Timestamp of last update",
|
||||||
|
null=True,
|
||||||
|
verbose_name="Updated",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"model_id",
|
||||||
|
models.PositiveIntegerField(
|
||||||
|
help_text="ID of the target model for this parameter",
|
||||||
|
verbose_name="Model ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"data",
|
||||||
|
models.CharField(
|
||||||
|
help_text="Parameter Value",
|
||||||
|
max_length=500,
|
||||||
|
validators=[django.core.validators.MinLengthValidator(1)],
|
||||||
|
verbose_name="Data",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"data_numeric",
|
||||||
|
models.FloatField(blank=True, default=None, null=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"note",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Optional note field",
|
||||||
|
max_length=500,
|
||||||
|
verbose_name="Note",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"model_type",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to="contenttypes.contenttype",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"updated_by",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
help_text="User who last updated this object",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="%(class)s_updated",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
verbose_name="Update By",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"template",
|
||||||
|
models.ForeignKey(
|
||||||
|
help_text="Parameter template",
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="parameters",
|
||||||
|
to="common.parametertemplate",
|
||||||
|
verbose_name="Template",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Parameter",
|
||||||
|
"verbose_name_plural": "Parameters",
|
||||||
|
"db_table": "part_partparameter",
|
||||||
|
"indexes": [
|
||||||
|
models.Index(
|
||||||
|
fields=["model_type", "model_id"],
|
||||||
|
name="part_partpa_model_t_198c9d_idx",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
"unique_together": {("model_type", "model_id", "template")},
|
||||||
|
},
|
||||||
|
bases=(
|
||||||
|
InvenTree.models.ContentTypeMixin,
|
||||||
|
InvenTree.models.PluginValidationMixin,
|
||||||
|
models.Model,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
database_operations=[],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,229 +0,0 @@
|
|||||||
# Generated by Django 4.2.25 on 2025-10-28 11:12
|
|
||||||
|
|
||||||
import structlog
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
logger = structlog.get_logger('inventree')
|
|
||||||
|
|
||||||
|
|
||||||
def convert_to_numeric_value(value: str, units: str):
|
|
||||||
"""Convert a value (with units) to a numeric value.
|
|
||||||
|
|
||||||
Defaults to zero if the value cannot be converted.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import InvenTree.conversion
|
|
||||||
|
|
||||||
# Default value is null
|
|
||||||
result = None
|
|
||||||
|
|
||||||
if units:
|
|
||||||
try:
|
|
||||||
result = InvenTree.conversion.convert_physical_value(value, units)
|
|
||||||
result = float(result.magnitude)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
result = float(value)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def update_global_setting(apps, schema_editor):
|
|
||||||
"""Update global setting key from PART_PARAMETER_ENFORCE_UNITS to PARAMETER_ENFORCE_UNITS."""
|
|
||||||
GlobalSetting = apps.get_model("common", "InvenTreeSetting")
|
|
||||||
|
|
||||||
OLD_KEY = 'PART_PARAMETER_ENFORCE_UNITS'
|
|
||||||
NEW_KEY = 'PARAMETER_ENFORCE_UNITS'
|
|
||||||
|
|
||||||
try:
|
|
||||||
setting = GlobalSetting.objects.get(key=OLD_KEY)
|
|
||||||
|
|
||||||
if setting is not None:
|
|
||||||
# Remove any existing new key
|
|
||||||
GlobalSetting.objects.filter(key=NEW_KEY).delete()
|
|
||||||
setting.key = NEW_KEY
|
|
||||||
setting.save()
|
|
||||||
logger.info(f"Updated global setting key from {OLD_KEY} to {NEW_KEY}.")
|
|
||||||
except GlobalSetting.DoesNotExist:
|
|
||||||
logger.info(f"Global setting {OLD_KEY} does not exist; no update needed.")
|
|
||||||
|
|
||||||
|
|
||||||
def remove_existing_parameters(apps, schema_editor):
|
|
||||||
"""Remove any existing Parameter or ParameterTemplate objects from the database."""
|
|
||||||
|
|
||||||
Parameter = apps.get_model("common", "Parameter")
|
|
||||||
ParameterTemplate = apps.get_model("common", "ParameterTemplate")
|
|
||||||
|
|
||||||
n_params = Parameter.objects.count()
|
|
||||||
n_templates = ParameterTemplate.objects.count()
|
|
||||||
|
|
||||||
Parameter.objects.all().delete()
|
|
||||||
ParameterTemplate.objects.all().delete()
|
|
||||||
|
|
||||||
if n_params > 0:
|
|
||||||
logger.info(f"Removed {n_params} existing Parameter instances.")
|
|
||||||
|
|
||||||
if n_templates > 0:
|
|
||||||
logger.info(f"Removed {n_templates} existing ParameterTemplate instances.")
|
|
||||||
|
|
||||||
assert Parameter.objects.count() == 0
|
|
||||||
assert ParameterTemplate.objects.count() == 0
|
|
||||||
|
|
||||||
|
|
||||||
def copy_part_parameters(apps, schema_editor):
|
|
||||||
"""Forward migration: copy from PartParameterTemplate to ParameterTemplate."""
|
|
||||||
|
|
||||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
|
||||||
PartParameterTemplate = apps.get_model("part", "PartParameterTemplate")
|
|
||||||
ParameterTemplate = apps.get_model("common", "ParameterTemplate")
|
|
||||||
PartParameter = apps.get_model("part", "PartParameter")
|
|
||||||
Parameter = apps.get_model("common", "Parameter")
|
|
||||||
|
|
||||||
# First, create a ParameterTemplate instance for each PartParameterTemplate
|
|
||||||
templates = []
|
|
||||||
|
|
||||||
for template in PartParameterTemplate.objects.all():
|
|
||||||
templates.append(ParameterTemplate(
|
|
||||||
name=template.name,
|
|
||||||
description=template.description,
|
|
||||||
units=template.units or '',
|
|
||||||
checkbox=template.checkbox,
|
|
||||||
choices=template.choices,
|
|
||||||
selectionlist=template.selectionlist,
|
|
||||||
model_type=None
|
|
||||||
))
|
|
||||||
|
|
||||||
if len(templates) > 0:
|
|
||||||
ParameterTemplate.objects.bulk_create(templates)
|
|
||||||
logger.info(f"\nMigrated {len(templates)} PartParameterTemplate instances.")
|
|
||||||
|
|
||||||
assert ParameterTemplate.objects.all().count() == len(templates)
|
|
||||||
|
|
||||||
# Next, copy PartParameter instances to Parameter instances
|
|
||||||
parameters = []
|
|
||||||
|
|
||||||
content_type, _created = ContentType.objects.get_or_create(app_label='part', model='part')
|
|
||||||
|
|
||||||
for parameter in PartParameter.objects.all():
|
|
||||||
# Find the corresponding ParameterTemplate
|
|
||||||
template = ParameterTemplate.objects.get(name=parameter.template.name)
|
|
||||||
|
|
||||||
parameters.append(Parameter(
|
|
||||||
template=template,
|
|
||||||
model_type=content_type,
|
|
||||||
model_id=parameter.part.id,
|
|
||||||
data=parameter.data,
|
|
||||||
data_numeric=parameter.data_numeric,
|
|
||||||
note=parameter.note,
|
|
||||||
metadata=parameter.metadata,
|
|
||||||
updated=parameter.updated,
|
|
||||||
updated_by=parameter.updated_by
|
|
||||||
))
|
|
||||||
|
|
||||||
if len(parameters) > 0:
|
|
||||||
Parameter.objects.bulk_create(parameters)
|
|
||||||
logger.info(f"\nMigrated {len(parameters)} PartParameter instances.")
|
|
||||||
|
|
||||||
assert Parameter.objects.filter(model_type=content_type).count() == len(parameters)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_manufacturer_part_parameters(apps, schema_editor):
|
|
||||||
"""Copy ManufacturerPartParameter to Parameter."""
|
|
||||||
|
|
||||||
ManufacturerPartParameter = apps.get_model("company", "ManufacturerPartParameter")
|
|
||||||
Parameter = apps.get_model("common", "Parameter")
|
|
||||||
ParameterTemplate = apps.get_model("common", "ParameterTemplate")
|
|
||||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
|
||||||
parameters = []
|
|
||||||
|
|
||||||
content_type, _created = ContentType.objects.get_or_create(app_label='company', model='manufacturerpart')
|
|
||||||
|
|
||||||
for parameter in ManufacturerPartParameter.objects.all():
|
|
||||||
# Find the corresponding ParameterTemplate
|
|
||||||
template = ParameterTemplate.objects.filter(name=parameter.name).first()
|
|
||||||
|
|
||||||
if not template:
|
|
||||||
# A matching template does not exist - let's create one
|
|
||||||
template = ParameterTemplate.objects.create(
|
|
||||||
name=parameter.name,
|
|
||||||
description='',
|
|
||||||
units=parameter.units or '',
|
|
||||||
model_type=None,
|
|
||||||
checkbox=False
|
|
||||||
)
|
|
||||||
|
|
||||||
parameters.append(Parameter(
|
|
||||||
template=template,
|
|
||||||
model_type=content_type,
|
|
||||||
model_id=parameter.manufacturer_part.id,
|
|
||||||
data=parameter.value,
|
|
||||||
data_numeric=convert_to_numeric_value(parameter.value, parameter.units),
|
|
||||||
))
|
|
||||||
|
|
||||||
if len(parameters) > 0:
|
|
||||||
Parameter.objects.bulk_create(parameters)
|
|
||||||
logger.info(f"\nMigrated {len(parameters)} ManufacturerPartParameter instances.")
|
|
||||||
|
|
||||||
assert Parameter.objects.filter(model_type=content_type).count() == len(parameters)
|
|
||||||
|
|
||||||
|
|
||||||
def update_category_parameters(apps, schema_editor):
|
|
||||||
"""Migration for PartCategoryParameterTemplate.
|
|
||||||
|
|
||||||
Copies the contents of the 'parameter_template' field to the new 'template' field
|
|
||||||
"""
|
|
||||||
|
|
||||||
PartCategoryParameterTemplate = apps.get_model("part", "partcategoryparametertemplate")
|
|
||||||
ParameterTemplate = apps.get_model("common", "parametertemplate")
|
|
||||||
|
|
||||||
to_update = []
|
|
||||||
|
|
||||||
for item in PartCategoryParameterTemplate.objects.all():
|
|
||||||
# Find a matching template
|
|
||||||
item.template = ParameterTemplate.objects.get(
|
|
||||||
name=item.parameter_template.name
|
|
||||||
)
|
|
||||||
|
|
||||||
to_update.append(item)
|
|
||||||
|
|
||||||
if len(to_update) > 0:
|
|
||||||
PartCategoryParameterTemplate.objects.bulk_update(to_update, ['template'])
|
|
||||||
logger.info(f"Updated {len(to_update)} PartCategoryParameterTemplate instances.")
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('contenttypes', '__latest__'),
|
|
||||||
("part", "0144_partcategoryparametertemplate_template"),
|
|
||||||
("company", "0076_alter_company_image"),
|
|
||||||
("common", "0040_parametertemplate_parameter"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(
|
|
||||||
update_global_setting,
|
|
||||||
reverse_code=migrations.RunPython.noop
|
|
||||||
),
|
|
||||||
migrations.RunPython(
|
|
||||||
remove_existing_parameters,
|
|
||||||
reverse_code=migrations.RunPython.noop
|
|
||||||
),
|
|
||||||
migrations.RunPython(
|
|
||||||
copy_part_parameters,
|
|
||||||
reverse_code=migrations.RunPython.noop
|
|
||||||
),
|
|
||||||
migrations.RunPython(
|
|
||||||
copy_manufacturer_part_parameters,
|
|
||||||
reverse_code=migrations.RunPython.noop
|
|
||||||
),
|
|
||||||
migrations.RunPython(
|
|
||||||
update_category_parameters,
|
|
||||||
reverse_code=migrations.RunPython.noop
|
|
||||||
)
|
|
||||||
]
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Generated by Django 5.2.8 on 2025-12-03 12:44
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
def convert_to_numeric_value(value: str, units: str):
|
||||||
|
"""Convert a value (with units) to a numeric value.
|
||||||
|
|
||||||
|
Defaults to zero if the value cannot be converted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import InvenTree.conversion
|
||||||
|
|
||||||
|
# Default value is null
|
||||||
|
result = None
|
||||||
|
|
||||||
|
if units:
|
||||||
|
try:
|
||||||
|
result = InvenTree.conversion.convert_physical_value(value, units)
|
||||||
|
result = float(result.magnitude)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
result = float(value)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def copy_manufacturer_part_parameters(apps, schema_editor):
|
||||||
|
"""Copy ManufacturerPartParameter to Parameter."""
|
||||||
|
|
||||||
|
ManufacturerPartParameter = apps.get_model("company", "ManufacturerPartParameter")
|
||||||
|
Parameter = apps.get_model("common", "Parameter")
|
||||||
|
ParameterTemplate = apps.get_model("common", "ParameterTemplate")
|
||||||
|
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||||
|
parameters = []
|
||||||
|
|
||||||
|
content_type, _created = ContentType.objects.get_or_create(app_label='company', model='manufacturerpart')
|
||||||
|
|
||||||
|
for parameter in ManufacturerPartParameter.objects.all():
|
||||||
|
# Find the corresponding ParameterTemplate
|
||||||
|
template = ParameterTemplate.objects.filter(name=parameter.name).first()
|
||||||
|
|
||||||
|
if not template:
|
||||||
|
# A matching template does not exist - let's create one
|
||||||
|
template = ParameterTemplate.objects.create(
|
||||||
|
name=parameter.name,
|
||||||
|
description='',
|
||||||
|
units=parameter.units or '',
|
||||||
|
model_type=None,
|
||||||
|
checkbox=False
|
||||||
|
)
|
||||||
|
|
||||||
|
parameters.append(Parameter(
|
||||||
|
template=template,
|
||||||
|
model_type=content_type,
|
||||||
|
model_id=parameter.manufacturer_part.id,
|
||||||
|
data=parameter.value,
|
||||||
|
data_numeric=convert_to_numeric_value(parameter.value, parameter.units),
|
||||||
|
))
|
||||||
|
|
||||||
|
if len(parameters) > 0:
|
||||||
|
Parameter.objects.bulk_create(parameters)
|
||||||
|
print(f"\nMigrated {len(parameters)} ManufacturerPartParameter instances.")
|
||||||
|
|
||||||
|
assert Parameter.objects.filter(model_type=content_type).count() == len(parameters)
|
||||||
|
|
||||||
|
|
||||||
|
def update_global_setting(apps, schema_editor):
|
||||||
|
"""Update global setting key from PART_PARAMETER_ENFORCE_UNITS to PARAMETER_ENFORCE_UNITS."""
|
||||||
|
GlobalSetting = apps.get_model("common", "InvenTreeSetting")
|
||||||
|
|
||||||
|
OLD_KEY = 'PART_PARAMETER_ENFORCE_UNITS'
|
||||||
|
NEW_KEY = 'PARAMETER_ENFORCE_UNITS'
|
||||||
|
|
||||||
|
try:
|
||||||
|
setting = GlobalSetting.objects.get(key=OLD_KEY)
|
||||||
|
|
||||||
|
if setting is not None:
|
||||||
|
# Remove any existing new key
|
||||||
|
GlobalSetting.objects.filter(key=NEW_KEY).delete()
|
||||||
|
setting.key = NEW_KEY
|
||||||
|
setting.save()
|
||||||
|
print(f"Updated global setting key from {OLD_KEY} to {NEW_KEY}.")
|
||||||
|
except GlobalSetting.DoesNotExist:
|
||||||
|
print(f"Global setting {OLD_KEY} does not exist; no update needed.")
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
"""Perform data migration for the ManufacturerPartParameter model."""
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("common", "0040_parametertemplate_parameter"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
update_global_setting,
|
||||||
|
reverse_code=migrations.RunPython.noop
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
copy_manufacturer_part_parameters,
|
||||||
|
reverse_code=migrations.RunPython.noop
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -2387,6 +2387,11 @@ class ParameterTemplate(
|
|||||||
verbose_name = _('Parameter Template')
|
verbose_name = _('Parameter Template')
|
||||||
verbose_name_plural = _('Parameter Templates')
|
verbose_name_plural = _('Parameter Templates')
|
||||||
|
|
||||||
|
# Note: Data was migrated from the existing 'part_partparametertemplate' table
|
||||||
|
# Ref: https://github.com/inventree/InvenTree/pull/10699
|
||||||
|
# To avoid data loss, we retain the existing table name
|
||||||
|
db_table = 'part_partparametertemplate'
|
||||||
|
|
||||||
class ModelChoices(RenderChoices):
|
class ModelChoices(RenderChoices):
|
||||||
"""Model choices for parameters."""
|
"""Model choices for parameters."""
|
||||||
|
|
||||||
@@ -2576,9 +2581,13 @@ class Parameter(
|
|||||||
verbose_name = _('Parameter')
|
verbose_name = _('Parameter')
|
||||||
verbose_name_plural = _('Parameters')
|
verbose_name_plural = _('Parameters')
|
||||||
unique_together = [['model_type', 'model_id', 'template']]
|
unique_together = [['model_type', 'model_id', 'template']]
|
||||||
|
|
||||||
indexes = [models.Index(fields=['model_type', 'model_id'])]
|
indexes = [models.Index(fields=['model_type', 'model_id'])]
|
||||||
|
|
||||||
|
# Note: Data was migrated from the existing 'part_partparameter' table
|
||||||
|
# Ref: https://github.com/inventree/InvenTree/pull/10699
|
||||||
|
# To avoid data loss, we retain the existing table name
|
||||||
|
db_table = 'part_partparameter'
|
||||||
|
|
||||||
class ModelChoices(RenderChoices):
|
class ModelChoices(RenderChoices):
|
||||||
"""Model choices for parameters."""
|
"""Model choices for parameters."""
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,15 @@ from django.db import migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
"""Remove the ManufacturerPartParameter model.
|
||||||
|
|
||||||
|
The data has been migrated to the common.Parameter model in a previous migration.
|
||||||
|
"""
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("company", "0076_alter_company_image"),
|
("company", "0076_alter_company_image"),
|
||||||
("common", "0041_auto_20251028_1112"),
|
("common", "0041_auto_20251203_1244"),
|
||||||
|
("part", "0146_auto_20251203_1241")
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|||||||
@@ -61,48 +61,6 @@ def reverse_update_parameter(apps, schema_editor):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_category_parameters(apps, schema_editor):
|
|
||||||
"""Copy the 'part_template' field to the new 'template' field."""
|
|
||||||
|
|
||||||
PartCategoryParameterTemplate = apps.get_model("part", "PartCategoryParameterTemplate")
|
|
||||||
|
|
||||||
category_parameters_to_update = []
|
|
||||||
|
|
||||||
for cat_param in PartCategoryParameterTemplate.objects.all():
|
|
||||||
cat_param.template = cat_param.part_template
|
|
||||||
category_parameters_to_update.append(cat_param)
|
|
||||||
|
|
||||||
if len(category_parameters_to_update) > 0:
|
|
||||||
|
|
||||||
print(f"Updating {len(category_parameters_to_update)} PartCategoryParameterTemplate records.")
|
|
||||||
|
|
||||||
PartCategoryParameterTemplate.objects.bulk_update(
|
|
||||||
category_parameters_to_update,
|
|
||||||
fields=["template"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def reverse_update_category_parameters(apps, schema_editor):
|
|
||||||
"""Copy the 'template' field back to the 'part_template' field."""
|
|
||||||
|
|
||||||
PartCategoryParameterTemplate = apps.get_model("part", "PartCategoryParameterTemplate")
|
|
||||||
|
|
||||||
category_parameters_to_update = []
|
|
||||||
|
|
||||||
for cat_param in PartCategoryParameterTemplate.objects.all():
|
|
||||||
cat_param.part_template = cat_param.template
|
|
||||||
category_parameters_to_update.append(cat_param)
|
|
||||||
|
|
||||||
if len(category_parameters_to_update) > 0:
|
|
||||||
|
|
||||||
print(f"Reversing update of {len(category_parameters_to_update)} PartCategoryParameterTemplate records.")
|
|
||||||
|
|
||||||
PartCategoryParameterTemplate.objects.bulk_update(
|
|
||||||
category_parameters_to_update,
|
|
||||||
fields=["part_template"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
"""Data migration for making the PartParameterTemplate and PartParameter models generic.
|
"""Data migration for making the PartParameterTemplate and PartParameter models generic.
|
||||||
|
|
||||||
@@ -168,49 +126,32 @@ class Migration(migrations.Migration):
|
|||||||
update_parameter,
|
update_parameter,
|
||||||
reverse_code=reverse_update_parameter,
|
reverse_code=reverse_update_parameter,
|
||||||
),
|
),
|
||||||
# Add a new "template" field to the PartCategoryParameterTemplate model
|
# Update the "model_type" field on the PartParameter model to be non-nullable
|
||||||
migrations.AddField(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="template",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=deletion.CASCADE,
|
|
||||||
related_name="part_categories",
|
|
||||||
to="common.parametertemplate",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
# Remove unique constraint on PartCategoryParameterTemplate model
|
|
||||||
migrations.RemoveConstraint(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="unique_category_parameter_template_pair",
|
|
||||||
),
|
|
||||||
# Perform data migration for the PartCategoryParameterTemplate model
|
|
||||||
migrations.RunPython(
|
|
||||||
update_category_parameters,
|
|
||||||
reverse_code=reverse_update_category_parameters,
|
|
||||||
),
|
|
||||||
# Remove the obsolete "part_template" field from the PartCategoryParameterTemplate model
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="parameter_template",
|
|
||||||
),
|
|
||||||
# Remove nullable attribute from the new 'template' field
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="partcategoryparametertemplate",
|
model_name="partparameter",
|
||||||
name="template",
|
name="model_type",
|
||||||
field=models.ForeignKey(
|
field=models.ForeignKey(
|
||||||
on_delete=deletion.CASCADE,
|
on_delete=deletion.CASCADE,
|
||||||
related_name="part_categories",
|
to="contenttypes.contenttype",
|
||||||
to="common.parametertemplate",
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
# Update uniqueness constraint on PartCategoryParameterTemplate model
|
# Update the "model_id" field on the PartParameter model to be non-nullable
|
||||||
migrations.AddConstraint(
|
migrations.AlterField(
|
||||||
model_name="partcategoryparametertemplate",
|
model_name="partparameter",
|
||||||
constraint=models.UniqueConstraint(
|
name="model_id",
|
||||||
fields=("category", "template"),
|
field=models.PositiveIntegerField(
|
||||||
name="unique_category_parameter_pair",
|
help_text="ID of the target model for this parameter",
|
||||||
),
|
verbose_name="Model ID",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
# Remove the "unique_together" constraint on the PartParameter model
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name="partparameter",
|
||||||
|
unique_together={('model_type', 'model_id', 'template')},
|
||||||
|
),
|
||||||
|
# Remove the obsolete "part" field from the PartParameter model
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="partparameter",
|
||||||
|
name="part",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
# Generated by Django 5.2.8 on 2025-11-25 06:19
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("part", "0143_alter_part_image"),
|
|
||||||
("common", "0040_parametertemplate_parameter"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="template",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="part_categories",
|
|
||||||
to="common.parametertemplate",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.RemoveConstraint(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="unique_category_parameter_template_pair",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# Generated by Django 5.2.8 on 2025-12-03 11:20
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
from django.db.models import deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("part", "0144_auto_20251203_1045"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
# Update the "model_type" field on the PartParameter model to be non-nullable
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="partparameter",
|
|
||||||
name="model_type",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
on_delete=deletion.CASCADE,
|
|
||||||
to="contenttypes.contenttype",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
# Update the "model_id" field on the PartParameter model to be non-nullable
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="partparameter",
|
|
||||||
name="model_id",
|
|
||||||
field=models.PositiveIntegerField(
|
|
||||||
help_text="ID of the target model for this parameter",
|
|
||||||
verbose_name="Model ID",
|
|
||||||
)
|
|
||||||
),
|
|
||||||
# Remove the "unique_together" constraint on the PartParameter model
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name="partparameter",
|
|
||||||
unique_together={('model_type', 'model_id', 'template')},
|
|
||||||
),
|
|
||||||
# Remove the obsolete "part" field from the PartParameter model
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partparameter",
|
|
||||||
name="part",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
106
src/backend/InvenTree/part/migrations/0145_auto_20251203_1238.py
Normal file
106
src/backend/InvenTree/part/migrations/0145_auto_20251203_1238.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Generated by Django 5.2.8 on 2025-12-03 12:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.models import deletion
|
||||||
|
|
||||||
|
|
||||||
|
def update_category_parameters(apps, schema_editor):
|
||||||
|
"""Copy the 'parameter_template' field to the new 'template' field."""
|
||||||
|
|
||||||
|
PartCategoryParameterTemplate = apps.get_model("part", "PartCategoryParameterTemplate")
|
||||||
|
ParameterTemplate = apps.get_model("common", "ParameterTemplate")
|
||||||
|
|
||||||
|
category_parameters_to_update = []
|
||||||
|
|
||||||
|
for cat_param in PartCategoryParameterTemplate.objects.all():
|
||||||
|
template = ParameterTemplate.objects.get(pk=cat_param.parameter_template_id)
|
||||||
|
cat_param.template = template
|
||||||
|
category_parameters_to_update.append(cat_param)
|
||||||
|
|
||||||
|
if len(category_parameters_to_update) > 0:
|
||||||
|
|
||||||
|
print(f"Updating {len(category_parameters_to_update)} PartCategoryParameterTemplate records.")
|
||||||
|
|
||||||
|
PartCategoryParameterTemplate.objects.bulk_update(
|
||||||
|
category_parameters_to_update,
|
||||||
|
fields=["template"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_update_category_parameters(apps, schema_editor):
|
||||||
|
"""Copy the 'template' field back to the 'parameter_template' field."""
|
||||||
|
|
||||||
|
PartParameterTemplate = apps.get_model("part", "PartParameterTemplate")
|
||||||
|
PartCategoryParameterTemplate = apps.get_model("part", "PartCategoryParameterTemplate")
|
||||||
|
|
||||||
|
category_parameters_to_update = []
|
||||||
|
|
||||||
|
for cat_param in PartCategoryParameterTemplate.objects.all():
|
||||||
|
template = PartParameterTemplate.objects.get(pk=cat_param.template_id)
|
||||||
|
cat_param.parameter_template = template
|
||||||
|
category_parameters_to_update.append(cat_param)
|
||||||
|
|
||||||
|
if len(category_parameters_to_update) > 0:
|
||||||
|
|
||||||
|
print(f"Reversing update of {len(category_parameters_to_update)} PartCategoryParameterTemplate records.")
|
||||||
|
|
||||||
|
PartCategoryParameterTemplate.objects.bulk_update(
|
||||||
|
category_parameters_to_update,
|
||||||
|
fields=["parameter_template"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("part", "0144_auto_20251203_1045"),
|
||||||
|
("common", "0040_parametertemplate_parameter")
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
# Add a new "template" field to the PartCategoryParameterTemplate model
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="partcategoryparametertemplate",
|
||||||
|
name="template",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=deletion.CASCADE,
|
||||||
|
related_name="part_categories",
|
||||||
|
to="common.parametertemplate",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Remove unique constraint on PartCategoryParameterTemplate model
|
||||||
|
migrations.RemoveConstraint(
|
||||||
|
model_name="partcategoryparametertemplate",
|
||||||
|
name="unique_category_parameter_template_pair",
|
||||||
|
),
|
||||||
|
# Perform data migration for the PartCategoryParameterTemplate model
|
||||||
|
migrations.RunPython(
|
||||||
|
update_category_parameters,
|
||||||
|
reverse_code=reverse_update_category_parameters,
|
||||||
|
),
|
||||||
|
# Remove the obsolete "part_template" field from the PartCategoryParameterTemplate model
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="partcategoryparametertemplate",
|
||||||
|
name="parameter_template",
|
||||||
|
),
|
||||||
|
# Remove nullable attribute from the new 'template' field
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="partcategoryparametertemplate",
|
||||||
|
name="template",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=deletion.CASCADE,
|
||||||
|
related_name="part_categories",
|
||||||
|
to="common.parametertemplate",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Update uniqueness constraint on PartCategoryParameterTemplate model
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name="partcategoryparametertemplate",
|
||||||
|
constraint=models.UniqueConstraint(
|
||||||
|
fields=("category", "template"),
|
||||||
|
name="unique_category_parameter_pair",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# Generated by Django 5.2.8 on 2025-11-25 07:01
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("common", "0041_auto_20251028_1112"),
|
|
||||||
("part", "0144_partcategoryparametertemplate_template"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partparametertemplate",
|
|
||||||
name="selectionlist",
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="parameter_template",
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
name="template",
|
|
||||||
field=models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="part_categories",
|
|
||||||
to="common.parametertemplate",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AddConstraint(
|
|
||||||
model_name="partcategoryparametertemplate",
|
|
||||||
constraint=models.UniqueConstraint(
|
|
||||||
fields=("category", "template"),
|
|
||||||
name="unique_category_parameter_pair",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name="PartParameter",
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name="PartParameterTemplate",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.2.8 on 2025-12-03 12:41
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("part", "0145_auto_20251203_1238"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Remove the PartParameterTemplate and PartParameter models
|
||||||
|
# Note: We *DO NOT* drop the underlying database tables,
|
||||||
|
# as these are now used by the common.ParameterTemplate and common.Parameter models
|
||||||
|
operations = [
|
||||||
|
migrations.SeparateDatabaseAndState(
|
||||||
|
state_operations=[
|
||||||
|
migrations.DeleteModel(name='PartParameterTemplate'),
|
||||||
|
migrations.DeleteModel(name='PartParameter'),
|
||||||
|
],
|
||||||
|
database_operations=[]
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 5.2.8 on 2025-12-03 12:00
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("part", "0145_auto_20251203_1120"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partparametertemplate",
|
|
||||||
name="model_type",
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="partparametertemplate",
|
|
||||||
name="selectionlist",
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name="PartParameter",
|
|
||||||
options={
|
|
||||||
"managed": False,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name="PartParameterTemplate",
|
|
||||||
options={
|
|
||||||
"managed": False,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Reference in New Issue
Block a user