first commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import IrrigationMethod
|
||||
|
||||
|
||||
@admin.register(IrrigationMethod)
|
||||
class IrrigationMethodAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"id",
|
||||
"name",
|
||||
"category",
|
||||
"water_efficiency_percent",
|
||||
"soil_type",
|
||||
"climate_suitability",
|
||||
"created_at",
|
||||
)
|
||||
list_filter = ("category", "climate_suitability")
|
||||
search_fields = ("name", "category")
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IrrigationConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "irrigation"
|
||||
verbose_name = "Irrigation"
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Management command to seed initial irrigation methods.
|
||||
Run: python manage.py seed_irrigation_methods
|
||||
"""
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from irrigation.models import IrrigationMethod
|
||||
|
||||
|
||||
INITIAL_METHODS = [
|
||||
{
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آب با دبی کم و بهصورت قطرهای مستقیماً به ریشه گیاه رسانده میشود. مناسبترین روش برای مناطق خشک و کمآب.",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "تمام انواع خاک",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
},
|
||||
{
|
||||
"name": "آبیاری بارانی",
|
||||
"category": "تحت فشار",
|
||||
"description": "آب تحت فشار از طریق آبپاشها بهصورت قطرات ریز مانند باران پخش میشود.",
|
||||
"water_efficiency_percent": 75.0,
|
||||
"water_pressure_required": "۲-۴ اتمسفر",
|
||||
"flow_rate": "۵-۲۰ لیتر در دقیقه",
|
||||
"coverage_area": "۱۰-۳۰ متر شعاع پاشش",
|
||||
"soil_type": "لومی، لومی شنی",
|
||||
"climate_suitability": "معتدل، مرطوب",
|
||||
},
|
||||
{
|
||||
"name": "آبیاری سطحی (غرقابی)",
|
||||
"category": "سطحی",
|
||||
"description": "آب در سطح زمین جاری شده و بهصورت ثقلی زمین را آبیاری میکند. سادهترین و قدیمیترین روش.",
|
||||
"water_efficiency_percent": 50.0,
|
||||
"water_pressure_required": "نیاز به فشار ندارد (ثقلی)",
|
||||
"flow_rate": "متغیر بر اساس شیب زمین",
|
||||
"coverage_area": "وابسته به اندازه کرت",
|
||||
"soil_type": "رسی، لومی رسی",
|
||||
"climate_suitability": "تمام اقلیمها (مناطق پرآب)",
|
||||
},
|
||||
{
|
||||
"name": "آبیاری نشتی (تیپ)",
|
||||
"category": "موضعی",
|
||||
"description": "آب از طریق نوارهای تیپ با منافذ ریز بهصورت نشتی به خاک رسانده میشود.",
|
||||
"water_efficiency_percent": 85.0,
|
||||
"water_pressure_required": "۰.۵-۱.۵ اتمسفر",
|
||||
"flow_rate": "۱-۴ لیتر در ساعت به ازای هر متر",
|
||||
"coverage_area": "ردیفی، مناسب زراعت",
|
||||
"soil_type": "لومی، لومی شنی",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
},
|
||||
{
|
||||
"name": "آبیاری زیرسطحی",
|
||||
"category": "موضعی",
|
||||
"description": "لولههای آبیاری در زیر سطح خاک کار گذاشته شده و آب مستقیماً به منطقه ریشه میرسد.",
|
||||
"water_efficiency_percent": 95.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۱-۴ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی",
|
||||
"soil_type": "لومی، لومی رسی",
|
||||
"climate_suitability": "تمام اقلیمها",
|
||||
},
|
||||
{
|
||||
"name": "آبیاری بابلر",
|
||||
"category": "موضعی",
|
||||
"description": "آب با دبی بیشتر از قطرهای ولی کمتر از بارانی، بهصورت حبابی در پای درخت پخش میشود. مناسب درختان میوه.",
|
||||
"water_efficiency_percent": 80.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۸-۶۰ لیتر در ساعت",
|
||||
"coverage_area": "شعاع ۱-۲ متر اطراف درخت",
|
||||
"soil_type": "لومی، لومی رسی",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Seed initial irrigation methods (6 common methods)"
|
||||
|
||||
def handle(self, *args, **options):
|
||||
created_count = 0
|
||||
for method_data in INITIAL_METHODS:
|
||||
_, created = IrrigationMethod.objects.get_or_create(
|
||||
name=method_data["name"],
|
||||
defaults=method_data,
|
||||
)
|
||||
if created:
|
||||
created_count += 1
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f" Created: {method_data['name']}")
|
||||
)
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
f"\nDone. Created {created_count} new irrigation methods."
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
# Generated by Django 5.2.12 on 2026-03-19 15:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IrrigationMethod',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(db_index=True, help_text='نام روش آبیاری (قطره\u200cای، بارانی، سطحی و …)', max_length=255, unique=True)),
|
||||
('category', models.CharField(blank=True, help_text='نوع روش (موضعی، تحت فشار، سطحی)', max_length=255)),
|
||||
('description', models.TextField(blank=True, help_text='توضیحات کامل روش')),
|
||||
('water_efficiency_percent', models.FloatField(blank=True, help_text='راندمان مصرف آب (%)', null=True)),
|
||||
('water_pressure_required', models.CharField(blank=True, help_text='فشار مورد نیاز آب', max_length=255)),
|
||||
('flow_rate', models.CharField(blank=True, help_text='دبی یا میزان جریان آب', max_length=255)),
|
||||
('coverage_area', models.CharField(blank=True, help_text='مساحت قابل پوشش', max_length=255)),
|
||||
('soil_type', models.CharField(blank=True, help_text='نوع خاک مناسب', max_length=255)),
|
||||
('climate_suitability', models.CharField(blank=True, help_text='اقلیم مناسب', max_length=255)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'روش آبیاری',
|
||||
'verbose_name_plural': 'روش\u200cهای آبیاری',
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class IrrigationMethod(models.Model):
|
||||
"""
|
||||
روشهای آبیاری شامل مشخصات فنی.
|
||||
"""
|
||||
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
unique=True,
|
||||
db_index=True,
|
||||
help_text="نام روش آبیاری (قطرهای، بارانی، سطحی و …)",
|
||||
)
|
||||
category = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="نوع روش (موضعی، تحت فشار، سطحی)",
|
||||
)
|
||||
description = models.TextField(
|
||||
blank=True,
|
||||
help_text="توضیحات کامل روش",
|
||||
)
|
||||
water_efficiency_percent = models.FloatField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="راندمان مصرف آب (%)",
|
||||
)
|
||||
water_pressure_required = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="فشار مورد نیاز آب",
|
||||
)
|
||||
flow_rate = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="دبی یا میزان جریان آب",
|
||||
)
|
||||
coverage_area = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="مساحت قابل پوشش",
|
||||
)
|
||||
soil_type = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="نوع خاک مناسب",
|
||||
)
|
||||
climate_suitability = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text="اقلیم مناسب",
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["name"]
|
||||
verbose_name = "روش آبیاری"
|
||||
verbose_name_plural = "روشهای آبیاری"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -0,0 +1,25 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import IrrigationMethod
|
||||
|
||||
|
||||
class IrrigationMethodSerializer(serializers.ModelSerializer):
|
||||
"""سریالایزر خروجی / ورودی برای IrrigationMethod."""
|
||||
|
||||
class Meta:
|
||||
model = IrrigationMethod
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"category",
|
||||
"description",
|
||||
"water_efficiency_percent",
|
||||
"water_pressure_required",
|
||||
"flow_rate",
|
||||
"coverage_area",
|
||||
"soil_type",
|
||||
"climate_suitability",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
read_only_fields = ["id", "created_at", "updated_at"]
|
||||
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import IrrigationMethodDetailView, IrrigationMethodListCreateView
|
||||
|
||||
urlpatterns = [
|
||||
path("", IrrigationMethodListCreateView.as_view(), name="irrigation-list-create"),
|
||||
path("<int:pk>/", IrrigationMethodDetailView.as_view(), name="irrigation-detail"),
|
||||
]
|
||||
@@ -0,0 +1,180 @@
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiExample,
|
||||
OpenApiResponse,
|
||||
extend_schema,
|
||||
)
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .models import IrrigationMethod
|
||||
from .serializers import IrrigationMethodSerializer
|
||||
|
||||
|
||||
class IrrigationMethodListCreateView(APIView):
|
||||
"""لیست تمام روشهای آبیاری و ایجاد روش جدید."""
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="لیست روشهای آبیاری",
|
||||
description="لیست تمام روشهای آبیاری ذخیرهشده را برمیگرداند.",
|
||||
responses={200: IrrigationMethodSerializer(many=True)},
|
||||
)
|
||||
def get(self, request):
|
||||
methods = IrrigationMethod.objects.all()
|
||||
serializer = IrrigationMethodSerializer(methods, many=True)
|
||||
return Response(
|
||||
{"code": 200, "msg": "success", "data": serializer.data},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="ایجاد روش آبیاری جدید",
|
||||
description="یک روش آبیاری جدید ایجاد میکند.",
|
||||
request=IrrigationMethodSerializer,
|
||||
responses={
|
||||
201: IrrigationMethodSerializer,
|
||||
400: OpenApiResponse(description="داده نامعتبر"),
|
||||
},
|
||||
examples=[
|
||||
OpenApiExample(
|
||||
"نمونه درخواست",
|
||||
value={
|
||||
"name": "آبیاری قطرهای",
|
||||
"category": "موضعی",
|
||||
"description": "آبیاری با دبی کم و فشار مناسب",
|
||||
"water_efficiency_percent": 90.0,
|
||||
"water_pressure_required": "۱-۲ اتمسفر",
|
||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
||||
"coverage_area": "بسته به طراحی سیستم",
|
||||
"soil_type": "تمام انواع خاک",
|
||||
"climate_suitability": "گرم و خشک",
|
||||
},
|
||||
request_only=True,
|
||||
),
|
||||
],
|
||||
)
|
||||
def post(self, request):
|
||||
serializer = IrrigationMethodSerializer(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return Response(
|
||||
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
serializer.save()
|
||||
return Response(
|
||||
{"code": 201, "msg": "success", "data": serializer.data},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class IrrigationMethodDetailView(APIView):
|
||||
"""دریافت، ویرایش و حذف یک روش آبیاری."""
|
||||
|
||||
def _get_method(self, pk):
|
||||
return IrrigationMethod.objects.filter(pk=pk).first()
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="جزئیات روش آبیاری",
|
||||
description="مشخصات یک روش آبیاری را بر اساس شناسه برمیگرداند.",
|
||||
responses={
|
||||
200: IrrigationMethodSerializer,
|
||||
404: OpenApiResponse(description="روش آبیاری یافت نشد"),
|
||||
},
|
||||
)
|
||||
def get(self, request, pk):
|
||||
method = self._get_method(pk)
|
||||
if not method:
|
||||
return Response(
|
||||
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
serializer = IrrigationMethodSerializer(method)
|
||||
return Response(
|
||||
{"code": 200, "msg": "success", "data": serializer.data},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="ویرایش کامل روش آبیاری",
|
||||
description="تمام فیلدهای یک روش آبیاری را آپدیت میکند.",
|
||||
request=IrrigationMethodSerializer,
|
||||
responses={
|
||||
200: IrrigationMethodSerializer,
|
||||
400: OpenApiResponse(description="داده نامعتبر"),
|
||||
404: OpenApiResponse(description="روش آبیاری یافت نشد"),
|
||||
},
|
||||
)
|
||||
def put(self, request, pk):
|
||||
method = self._get_method(pk)
|
||||
if not method:
|
||||
return Response(
|
||||
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
serializer = IrrigationMethodSerializer(method, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return Response(
|
||||
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
serializer.save()
|
||||
return Response(
|
||||
{"code": 200, "msg": "success", "data": serializer.data},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="ویرایش جزئی روش آبیاری",
|
||||
description="فقط فیلدهای ارسالشده آپدیت میشوند.",
|
||||
request=IrrigationMethodSerializer,
|
||||
responses={
|
||||
200: IrrigationMethodSerializer,
|
||||
400: OpenApiResponse(description="داده نامعتبر"),
|
||||
404: OpenApiResponse(description="روش آبیاری یافت نشد"),
|
||||
},
|
||||
)
|
||||
def patch(self, request, pk):
|
||||
method = self._get_method(pk)
|
||||
if not method:
|
||||
return Response(
|
||||
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
serializer = IrrigationMethodSerializer(method, data=request.data, partial=True)
|
||||
if not serializer.is_valid():
|
||||
return Response(
|
||||
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
serializer.save()
|
||||
return Response(
|
||||
{"code": 200, "msg": "success", "data": serializer.data},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["Irrigation"],
|
||||
summary="حذف روش آبیاری",
|
||||
description="یک روش آبیاری را حذف میکند.",
|
||||
responses={
|
||||
200: OpenApiResponse(description="حذف موفق"),
|
||||
404: OpenApiResponse(description="روش آبیاری یافت نشد"),
|
||||
},
|
||||
)
|
||||
def delete(self, request, pk):
|
||||
method = self._get_method(pk)
|
||||
if not method:
|
||||
return Response(
|
||||
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
method.delete()
|
||||
return Response(
|
||||
{"code": 200, "msg": "روش آبیاری با موفقیت حذف شد.", "data": None},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
Reference in New Issue
Block a user