Harshit Pathak 3 місяців тому
батько
коміт
be30121eef

+ 42 - 0
attr_extraction/migrations/0002_productattribute_producttype_attributepossiblevalue_and_more.py

@@ -0,0 +1,42 @@
+# Generated by Django 5.2.7 on 2025-10-21 09:47
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('attr_extraction', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ProductAttribute',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=100)),
+                ('is_mandatory', models.BooleanField(default=False)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='ProductType',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=100, unique=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='AttributePossibleValue',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('value', models.CharField(max_length=255)),
+                ('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='possible_values', to='attr_extraction.productattribute')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='productattribute',
+            name='product_type',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='attr_extraction.producttype'),
+        ),
+    ]

+ 28 - 0
attr_extraction/models.py

@@ -14,3 +14,31 @@ class Product(models.Model):
 
     def __str__(self):
         return f"{self.product_name} ({self.item_id})"
+
+
+
+
+class ProductType(models.Model):
+    name = models.CharField(max_length=100, unique=True)
+
+    def __str__(self):
+        return self.name
+
+
+
+class ProductAttribute(models.Model):
+    product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE, related_name="attributes")
+    name = models.CharField(max_length=100)
+    is_mandatory = models.BooleanField(default=False)
+
+    def __str__(self):
+        return f"{self.product_type.name} - {self.name} ({'Mandatory' if self.is_mandatory else 'Additional'})"
+
+
+
+class AttributePossibleValue(models.Model):
+    attribute = models.ForeignKey(ProductAttribute, on_delete=models.CASCADE, related_name="possible_values")
+    value = models.CharField(max_length=255)
+
+    def __str__(self):
+        return f"{self.attribute.name}: {self.value}"

+ 2 - 1
attr_extraction/urls.py

@@ -1,11 +1,12 @@
 # ==================== urls.py ====================
 from django.urls import path
-from .views import ExtractProductAttributesView, BatchExtractProductAttributesView, ProductListView, ProductUploadExcelView
+from .views import ExtractProductAttributesView, ProductAttributesUploadView, BatchExtractProductAttributesView, ProductListView, ProductUploadExcelView
 
 urlpatterns = [
     path('extract/', ExtractProductAttributesView.as_view(), name='extract-attributes'),
     path('batch-extract/', BatchExtractProductAttributesView.as_view(), name='batch-extract-attributes'),
     path('products/', ProductListView.as_view(), name='batch-extract-attributes'),
     path('products/upload-excel/', ProductUploadExcelView.as_view(), name='product-upload-excel'),
+    path('products/upload-attributes/', ProductAttributesUploadView.as_view(), name='product-upload-excel'),
 
 ]

+ 65 - 0
attr_extraction/views.py

@@ -662,3 +662,68 @@ class ProductUploadExcelView(APIView):
 
         except Exception as e:
             return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+
+
+
+
+
+
+import pandas as pd
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+from rest_framework.parsers import MultiPartParser, FormParser
+from .models import ProductType, ProductAttribute, AttributePossibleValue
+
+
+class ProductAttributesUploadView(APIView):
+    """
+    POST API to upload an Excel file and add mandatory/additional attributes
+    for product types with possible values.
+    """
+    parser_classes = (MultiPartParser, FormParser)
+
+    def post(self, request):
+        file_obj = request.FILES.get('file')
+        if not file_obj:
+            return Response({"error": "No file provided."}, status=status.HTTP_400_BAD_REQUEST)
+
+        try:
+            df = pd.read_excel(file_obj)
+
+            required_columns = {'product_type', 'attribute_name', 'is_mandatory', 'possible_values'}
+            if not required_columns.issubset(df.columns):
+                return Response({
+                    "error": f"Missing required columns. Found: {list(df.columns)}"
+                }, status=status.HTTP_400_BAD_REQUEST)
+
+            for _, row in df.iterrows():
+                product_type_name = str(row['product_type']).strip()
+                attr_name = str(row['attribute_name']).strip()
+                is_mandatory = str(row['is_mandatory']).strip().lower() in ['yes', 'true', '1']
+                possible_values = str(row.get('possible_values', '')).strip()
+
+                # Get or create product type
+                product_type, _ = ProductType.objects.get_or_create(name=product_type_name)
+
+                # Get or create attribute
+                attribute, _ = ProductAttribute.objects.get_or_create(
+                    product_type=product_type,
+                    name=attr_name,
+                    defaults={'is_mandatory': is_mandatory}
+                )
+                attribute.is_mandatory = is_mandatory
+                attribute.save()
+
+                # Handle possible values
+                AttributePossibleValue.objects.filter(attribute=attribute).delete()
+                if possible_values:
+                    for val in [v.strip() for v in possible_values.split(',') if v.strip()]:
+                        AttributePossibleValue.objects.create(attribute=attribute, value=val)
+
+            return Response({"message": "Attributes uploaded successfully."}, status=status.HTTP_201_CREATED)
+
+        except Exception as e:
+            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)