UPDATE
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-19 15:01
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="FarmType",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("uuid", models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, unique=True)),
|
||||
("name", models.CharField(db_index=True, max_length=255, unique=True)),
|
||||
("description", models.TextField(blank=True, default="")),
|
||||
("metadata", models.JSONField(blank=True, default=dict)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
"db_table": "farm_types",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FarmHub",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("farm_uuid", models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, unique=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
("customization", models.JSONField(blank=True, default=dict)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"farm_type",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="farms",
|
||||
to="farm_hub.farmtype",
|
||||
),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="farm_hubs",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "farm_hubs",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Product",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("uuid", models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, unique=True)),
|
||||
("name", models.CharField(db_index=True, max_length=255)),
|
||||
("description", models.TextField(blank=True, default="")),
|
||||
("metadata", models.JSONField(blank=True, default=dict)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"farm_type",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="products",
|
||||
to="farm_hub.farmtype",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "products",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FarmSensor",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("uuid", models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, unique=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("sensor_type", models.CharField(blank=True, default="", max_length=255)),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
("specifications", models.JSONField(blank=True, default=dict)),
|
||||
("power_source", models.JSONField(blank=True, default=dict)),
|
||||
("customization", models.JSONField(blank=True, default=dict)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"farm",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="sensors",
|
||||
to="farm_hub.farmhub",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "farm_sensors",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="farmhub",
|
||||
name="products",
|
||||
field=models.ManyToManyField(blank=True, related_name="farms", to="farm_hub.product"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="product",
|
||||
constraint=models.UniqueConstraint(fields=("farm_type", "name"), name="unique_product_per_farm_type"),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
FARM_TYPES = {
|
||||
"زراعی": ["گندم", "ذرت", "جو", "کلزا", "پنبه"],
|
||||
"درختی": ["سیب", "پسته", "انگور", "انار"],
|
||||
"غرقابی": ["برنج"],
|
||||
"گلخانه ای": ["گوجه فرنگی", "خیار", "فلفل دلمه ای"],
|
||||
}
|
||||
|
||||
|
||||
def seed_catalog(apps, schema_editor):
|
||||
FarmType = apps.get_model("farm_hub", "FarmType")
|
||||
Product = apps.get_model("farm_hub", "Product")
|
||||
|
||||
for farm_type_name, products in FARM_TYPES.items():
|
||||
farm_type, _ = FarmType.objects.get_or_create(name=farm_type_name)
|
||||
for product_name in products:
|
||||
Product.objects.get_or_create(farm_type=farm_type, name=product_name)
|
||||
|
||||
|
||||
def unseed_catalog(apps, schema_editor):
|
||||
FarmType = apps.get_model("farm_hub", "FarmType")
|
||||
FarmType.objects.filter(name__in=FARM_TYPES.keys()).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(seed_catalog, unseed_catalog),
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-20 00:30
|
||||
|
||||
import uuid
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("device_hub", "0001_initial"),
|
||||
("farm_hub", "0002_seed_default_catalog"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="farmsensor",
|
||||
name="physical_device_uuid",
|
||||
field=models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="farmsensor",
|
||||
name="sensor_catalog",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="farm_sensors",
|
||||
to="device_hub.sensorcatalog",
|
||||
),
|
||||
),
|
||||
]
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-20 01:30
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("crop_zoning", "0004_croparea_farm"),
|
||||
("farm_hub", "0003_farmsensor_catalog_and_physical_device"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="farmhub",
|
||||
name="customization",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="farmsensor",
|
||||
name="customization",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="farmhub",
|
||||
name="current_crop_area",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="current_for_farms",
|
||||
to="crop_zoning.croparea",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,163 @@
|
||||
import json
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
DEFAULT_FARM_TYPE_NAME = "زراعی"
|
||||
|
||||
|
||||
def _table_exists(schema_editor, table_name):
|
||||
with schema_editor.connection.cursor() as cursor:
|
||||
existing_tables = set(schema_editor.connection.introspection.table_names(cursor))
|
||||
return table_name in existing_tables
|
||||
|
||||
|
||||
def _deserialize_json(value):
|
||||
if value in (None, "", b""):
|
||||
return {}
|
||||
if isinstance(value, (dict, list)):
|
||||
return value
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode("utf-8")
|
||||
try:
|
||||
return json.loads(value)
|
||||
except (TypeError, ValueError):
|
||||
return {}
|
||||
|
||||
|
||||
def migrate_plant_rows_to_products(apps, schema_editor):
|
||||
if not _table_exists(schema_editor, "plant_plant"):
|
||||
return
|
||||
|
||||
FarmType = apps.get_model("farm_hub", "FarmType")
|
||||
Product = apps.get_model("farm_hub", "Product")
|
||||
|
||||
farm_type, _ = FarmType.objects.get_or_create(name=DEFAULT_FARM_TYPE_NAME)
|
||||
|
||||
with schema_editor.connection.cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT
|
||||
name,
|
||||
light,
|
||||
watering,
|
||||
soil,
|
||||
temperature,
|
||||
planting_season,
|
||||
harvest_time,
|
||||
spacing,
|
||||
fertilizer,
|
||||
health_profile,
|
||||
irrigation_profile,
|
||||
growth_profile,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM plant_plant
|
||||
"""
|
||||
)
|
||||
columns = [column[0] for column in cursor.description]
|
||||
rows = [dict(zip(columns, row)) for row in cursor.fetchall()]
|
||||
|
||||
for row in rows:
|
||||
Product.objects.update_or_create(
|
||||
farm_type=farm_type,
|
||||
name=row["name"],
|
||||
defaults={
|
||||
"light": row["light"] or "",
|
||||
"watering": row["watering"] or "",
|
||||
"soil": row["soil"] or "",
|
||||
"temperature": row["temperature"] or "",
|
||||
"planting_season": row["planting_season"] or "",
|
||||
"harvest_time": row["harvest_time"] or "",
|
||||
"spacing": row["spacing"] or "",
|
||||
"fertilizer": row["fertilizer"] or "",
|
||||
"health_profile": _deserialize_json(row["health_profile"]),
|
||||
"irrigation_profile": _deserialize_json(row["irrigation_profile"]),
|
||||
"growth_profile": _deserialize_json(row["growth_profile"]),
|
||||
"created_at": row["created_at"],
|
||||
"updated_at": row["updated_at"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def drop_legacy_plant_table(apps, schema_editor):
|
||||
if _table_exists(schema_editor, "plant_plant"):
|
||||
schema_editor.execute("DROP TABLE plant_plant")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0004_remove_customization_add_current_crop_area"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="fertilizer",
|
||||
field=models.CharField(blank=True, default="", help_text="کود مناسب", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="growth_profile",
|
||||
field=models.JSONField(
|
||||
blank=True,
|
||||
default=dict,
|
||||
help_text='پروفایل رشد محصول برای مدل GDD. {"base_temperature": 10, "required_gdd_for_maturity": 1200, "stage_thresholds": {"flowering": 500, "fruiting": 850}, "current_cumulative_gdd": 320}',
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="harvest_time",
|
||||
field=models.CharField(blank=True, default="", help_text="زمان برداشت", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="health_profile",
|
||||
field=models.JSONField(
|
||||
blank=True,
|
||||
default=dict,
|
||||
help_text='پروفایل سلامت محصول برای KPIها. ساختار نمونه: {"moisture": {"ideal_value": 65, "min_range": 45, "max_range": 75, "weight": 0.4}}',
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="irrigation_profile",
|
||||
field=models.JSONField(
|
||||
blank=True,
|
||||
default=dict,
|
||||
help_text='پروفایل آبیاری محصول برای محاسبات ETc. {"kc_initial": 0.6, "kc_mid": 1.15, "kc_end": 0.8, "growth_stage_duration": {"initial": 20, "mid": 30, "late": 25}}',
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="light",
|
||||
field=models.CharField(blank=True, default="", help_text="نور مورد نیاز", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="planting_season",
|
||||
field=models.CharField(blank=True, default="", help_text="فصل کاشت", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="soil",
|
||||
field=models.CharField(blank=True, default="", help_text="خاک مناسب", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="spacing",
|
||||
field=models.CharField(blank=True, default="", help_text="فاصله کاشت", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="temperature",
|
||||
field=models.CharField(blank=True, default="", help_text="دمای مناسب", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="watering",
|
||||
field=models.CharField(blank=True, default="", help_text="آبیاری", max_length=255),
|
||||
),
|
||||
migrations.RunPython(migrate_plant_rows_to_products, migrations.RunPython.noop),
|
||||
migrations.RunPython(drop_legacy_plant_table, migrations.RunPython.noop),
|
||||
]
|
||||
@@ -0,0 +1,55 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
CATALOG_SEED_DATA = {
|
||||
"زراعی": [
|
||||
{"name": "گندم", "planting_season": "پاییز", "harvest_time": "اواخر بهار", "soil": "لومی"},
|
||||
{"name": "ذرت", "planting_season": "بهار", "harvest_time": "تابستان", "soil": "لومی شنی"},
|
||||
{"name": "جو", "planting_season": "پاییز", "harvest_time": "اواخر بهار", "soil": "لومی"},
|
||||
{"name": "کلزا", "planting_season": "پاییز", "harvest_time": "بهار", "soil": "لومی رسی"},
|
||||
{"name": "پنبه", "planting_season": "بهار", "harvest_time": "پاییز", "soil": "لومی"},
|
||||
],
|
||||
"درختی": [
|
||||
{"name": "سیب", "planting_season": "زمستان", "harvest_time": "پاییز", "soil": "لومی"},
|
||||
{"name": "پسته", "planting_season": "زمستان", "harvest_time": "اواخر تابستان", "soil": "شنی لومی"},
|
||||
{"name": "انگور", "planting_season": "اواخر زمستان", "harvest_time": "تابستان", "soil": "لومی"},
|
||||
{"name": "انار", "planting_season": "اواخر زمستان", "harvest_time": "پاییز", "soil": "لومی شنی"},
|
||||
],
|
||||
"غرقابی": [
|
||||
{"name": "برنج", "planting_season": "بهار", "harvest_time": "اواخر تابستان", "soil": "رسی"},
|
||||
],
|
||||
"گلخانه ای": [
|
||||
{"name": "گوجه فرنگی", "planting_season": "چهار فصل", "harvest_time": "چند مرحله ای", "soil": "کوکوپیت"},
|
||||
{"name": "خیار", "planting_season": "چهار فصل", "harvest_time": "چند مرحله ای", "soil": "پرلیت"},
|
||||
{"name": "فلفل دلمه ای", "planting_season": "چهار فصل", "harvest_time": "چند مرحله ای", "soil": "بستر هیدروپونیک"},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def seed_expanded_catalog(apps, schema_editor):
|
||||
FarmType = apps.get_model("farm_hub", "FarmType")
|
||||
Product = apps.get_model("farm_hub", "Product")
|
||||
|
||||
for farm_type_name, products in CATALOG_SEED_DATA.items():
|
||||
farm_type, _ = FarmType.objects.get_or_create(name=farm_type_name)
|
||||
for product_data in products:
|
||||
Product.objects.update_or_create(
|
||||
farm_type=farm_type,
|
||||
name=product_data["name"],
|
||||
defaults={key: value for key, value in product_data.items() if key != "name"},
|
||||
)
|
||||
|
||||
|
||||
def unseed_expanded_catalog(apps, schema_editor):
|
||||
FarmType = apps.get_model("farm_hub", "FarmType")
|
||||
FarmType.objects.filter(name__in=CATALOG_SEED_DATA.keys()).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0005_product_profiles_and_plant_migration"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(seed_expanded_catalog, unseed_expanded_catalog),
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 5.2.12 on 2026-04-03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0006_seed_expanded_product_catalog"),
|
||||
("access_control", "0002_link_subscription_plan_to_farm"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="farmhub",
|
||||
name="subscription_plan",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="farms",
|
||||
to="access_control.subscriptionplan",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0007_farmhub_subscription_plan"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="growth_stage",
|
||||
field=models.CharField(blank=True, default="", help_text="مرحله رشد فعلی", max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="growth_stages",
|
||||
field=models.JSONField(blank=True, default=list, help_text="فهرست مراحل رشد محصول"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="product",
|
||||
name="icon",
|
||||
field=models.CharField(blank=True, default="", help_text="آیکون محصول برای فرانت", max_length=100),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farm_hub", "0008_product_plant_selector_fields"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="farmhub",
|
||||
name="irrigation_method_id",
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="farmhub",
|
||||
name="irrigation_method_name",
|
||||
field=models.CharField(blank=True, default="", max_length=255),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("device_hub", "0001_initial"),
|
||||
("farm_hub", "0009_farmhub_irrigation_method_fields"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.SeparateDatabaseAndState(
|
||||
database_operations=[],
|
||||
state_operations=[
|
||||
migrations.DeleteModel(name="FarmSensor"),
|
||||
],
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user