Bläddra i källkod

new_updated feature

Harshit Pathak 3 månader sedan
förälder
incheckning
8d452d2495

+ 127 - 20
attr_extraction/admin.py

@@ -2,37 +2,144 @@ from django.contrib import admin
 from .models import Product, ProductType, ProductAttribute, AttributePossibleValue
 
 
+# @admin.register(Product)
+# class ProductAdmin(admin.ModelAdmin):
+#     list_display = ('item_id', 'product_name', 'product_type', 'image_path')
+#     search_fields = ('item_id', 'product_name', 'product_type')
+#     list_filter = ('product_type',)
+#     readonly_fields = ('image_path',)
+#     ordering = ('product_name',)
+ 
+
+
+class AttributePossibleValueInline(admin.TabularInline):
+    model = AttributePossibleValue
+    extra = 1
+
+
+# @admin.register(ProductAttribute)
+# class ProductAttributeAdmin(admin.ModelAdmin):
+#     list_display = ('name', 'product_type', 'is_mandatory')
+#     list_filter = ('product_type', 'is_mandatory')
+#     search_fields = ('name', 'product_type__name')
+#     inlines = [AttributePossibleValueInline]
+
+
+# @admin.register(AttributePossibleValue)
+# class AttributePossibleValueAdmin(admin.ModelAdmin):
+#     list_display = ('attribute', 'value')
+#     search_fields = ('attribute__name', 'value')
+#     list_filter = ('attribute__product_type',)
+
+
+
+
+# admin.py
+from django.contrib import admin
+from .models import Product, ProductType, ProductAttribute, AttributePossibleValue, ProductAttributeValue
+
+
+@admin.register(ProductAttributeValue)
+class ProductAttributeValueAdmin(admin.ModelAdmin):
+    """Admin interface for managing original attribute values."""
+    list_display = ['item_id_display', 'attribute_name', 'original_value', 'updated_at']
+    list_filter = ['attribute_name', 'created_at', 'updated_at']
+    search_fields = ['product__item_id', 'product__product_name', 'attribute_name', 'original_value']
+    readonly_fields = ['created_at', 'updated_at']
+    
+    fieldsets = (
+        ('Product Information', {
+            'fields': ('product',)
+        }),
+        ('Attribute Details', {
+            'fields': ('attribute_name', 'original_value')
+        }),
+        ('Timestamps', {
+            'fields': ('created_at', 'updated_at'),
+            'classes': ('collapse',)
+        }),
+    )
+    
+    def item_id_display(self, obj):
+        return obj.product.item_id
+    item_id_display.short_description = 'Item ID'
+    item_id_display.admin_order_field = 'product__item_id'
+    
+    def get_queryset(self, request):
+        """Optimize queries by selecting related product."""
+        return super().get_queryset(request).select_related('product')
+
+
+class ProductAttributeValueInline(admin.TabularInline):
+    """Inline admin for showing attribute values in Product admin."""
+    model = ProductAttributeValue
+    extra = 1
+    fields = ['attribute_name', 'original_value', 'updated_at']
+    readonly_fields = ['updated_at']
+
+
 @admin.register(Product)
 class ProductAdmin(admin.ModelAdmin):
-    list_display = ('item_id', 'product_name', 'product_type', 'image_path')
-    search_fields = ('item_id', 'product_name', 'product_type')
-    list_filter = ('product_type',)
-    readonly_fields = ('image_path',)
-    ordering = ('product_name',)
+    """Enhanced Product admin with inline attribute values."""
+    list_display = ['item_id', 'product_name', 'product_type', 'attribute_count']
+    list_filter = ['product_type']
+    search_fields = ['item_id', 'product_name', 'product_type']
+    inlines = [ProductAttributeValueInline]
+    
+    fieldsets = (
+        ('Basic Information', {
+            'fields': ('item_id', 'product_name', 'product_type')
+        }),
+        ('Descriptions', {
+            'fields': ('product_short_description', 'product_long_description'),
+            'classes': ('collapse',)
+        }),
+        ('Media', {
+            'fields': ('image_path', 'image')
+        }),
+    )
+    
+    def attribute_count(self, obj):
+        """Display count of original attribute values."""
+        return obj.attribute_values.count()
+    attribute_count.short_description = 'Original Attributes'
+    
+    def get_queryset(self, request):
+        """Optimize queries."""
+        return super().get_queryset(request).prefetch_related('attribute_values')
 
 
 @admin.register(ProductType)
 class ProductTypeAdmin(admin.ModelAdmin):
-    list_display = ('name',)
-    search_fields = ('name',)
-    ordering = ('name',)
-
-
-class AttributePossibleValueInline(admin.TabularInline):
-    model = AttributePossibleValue
-    extra = 1
+    list_display = ['name', 'attribute_count']
+    search_fields = ['name']
+    
+    def attribute_count(self, obj):
+        return obj.attributes.count()
+    attribute_count.short_description = 'Attributes'
 
 
 @admin.register(ProductAttribute)
 class ProductAttributeAdmin(admin.ModelAdmin):
-    list_display = ('name', 'product_type', 'is_mandatory')
-    list_filter = ('product_type', 'is_mandatory')
-    search_fields = ('name', 'product_type__name')
-    inlines = [AttributePossibleValueInline]
+    list_display = ['name', 'product_type', 'is_mandatory', 'possible_values_count']
+    list_filter = ['product_type', 'is_mandatory']
+    search_fields = ['name', 'product_type__name']
+    
+    def possible_values_count(self, obj):
+        return obj.possible_values.count()
+    possible_values_count.short_description = 'Possible Values'
 
 
 @admin.register(AttributePossibleValue)
 class AttributePossibleValueAdmin(admin.ModelAdmin):
-    list_display = ('attribute', 'value')
-    search_fields = ('attribute__name', 'value')
-    list_filter = ('attribute__product_type',)
+    list_display = ['value', 'attribute_name', 'product_type']
+    list_filter = ['attribute__product_type', 'attribute__name']
+    search_fields = ['value', 'attribute__name']
+    
+    def attribute_name(self, obj):
+        return obj.attribute.name
+    attribute_name.short_description = 'Attribute'
+    
+    def product_type(self, obj):
+        return obj.attribute.product_type.name
+    product_type.short_description = 'Product Type'

+ 28 - 0
attr_extraction/migrations/0003_productattributevalue.py

@@ -0,0 +1,28 @@
+# Generated by Django 5.2.7 on 2025-10-27 06:50
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('attr_extraction', '0002_productattribute_producttype_attributepossiblevalue_and_more'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ProductAttributeValue',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('attribute_name', models.CharField(max_length=100)),
+                ('original_value', models.TextField()),
+                ('created_at', models.DateTimeField(auto_now_add=True)),
+                ('updated_at', models.DateTimeField(auto_now=True)),
+                ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attribute_values', to='attr_extraction.product')),
+            ],
+            options={
+                'unique_together': {('product', 'attribute_name')},
+            },
+        ),
+    ]

+ 19 - 0
attr_extraction/models.py

@@ -16,6 +16,25 @@ class Product(models.Model):
         return f"{self.product_name} ({self.item_id})"
 
 
+# models.py
+
+class ProductAttributeValue(models.Model):
+    """
+    Stores manually entered original attribute values for products
+    """
+    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="attribute_values")
+    attribute_name = models.CharField(max_length=100)
+    original_value = models.TextField()
+    created_at = models.DateTimeField(auto_now_add=True)
+    updated_at = models.DateTimeField(auto_now=True)
+
+    class Meta:
+        unique_together = ['product', 'attribute_name']
+
+    def __str__(self):
+        return f"{self.product.item_id} - {self.attribute_name}: {self.original_value}"
+
+
 
 
 class ProductType(models.Model):

+ 80 - 1
attr_extraction/serializers.py

@@ -409,4 +409,83 @@ class ProductTypeSerializer(serializers.ModelSerializer):
     
     class Meta:
         model = ProductType
-        fields = ['name', 'attributes']
+        fields = ['name', 'attributes']
+
+
+
+
+
+# Add these new serializers to your serializers.py
+
+from rest_framework import serializers
+from .models import Product, ProductType, ProductAttribute, AttributePossibleValue, ProductAttributeValue
+
+
+class ProductAttributeValueSerializer(serializers.ModelSerializer):
+    """Serializer for manually entered attribute values."""
+    item_id = serializers.CharField(source='product.item_id', read_only=True)
+    
+    class Meta:
+        model = ProductAttributeValue
+        fields = ['id', 'item_id', 'attribute_name', 'original_value', 'created_at', 'updated_at']
+        read_only_fields = ['created_at', 'updated_at']
+
+
+class ProductAttributeValueInputSerializer(serializers.Serializer):
+    """Serializer for creating/updating attribute values."""
+    item_id = serializers.CharField(required=True)
+    attribute_name = serializers.CharField(required=True)
+    original_value = serializers.CharField(required=True, allow_blank=True)
+
+
+class BulkProductAttributeValueSerializer(serializers.Serializer):
+    """Serializer for bulk upload of attribute values."""
+    item_id = serializers.CharField(required=True)
+    attributes = serializers.DictField(
+        child=serializers.CharField(allow_blank=True),
+        required=True,
+        help_text="Dictionary of attribute_name: original_value pairs"
+    )
+
+
+class ProductWithAttributesSerializer(serializers.ModelSerializer):
+    """Extended Product serializer with original attribute values."""
+    product_type_details = serializers.SerializerMethodField()
+    original_attributes = serializers.SerializerMethodField()
+    
+    class Meta:
+        model = Product
+        fields = [
+            'id',
+            'item_id',
+            'product_name',
+            'product_long_description',
+            'product_short_description',
+            'product_type',
+            'image_path',
+            'image',
+            'product_type_details',
+            'original_attributes',
+        ]
+
+    def get_product_type_details(self, obj):
+        """Fetch ProductType object and its attributes for this product."""
+        try:
+            product_type = ProductType.objects.get(name=obj.product_type)
+        except ProductType.DoesNotExist:
+            return []
+
+        attributes = ProductAttribute.objects.filter(product_type=product_type)
+        return [
+            {
+                "attribute_name": attr.name,
+                "is_mandatory": "Yes" if attr.is_mandatory else "No",
+                "possible_values": [pv.value for pv in attr.possible_values.all()]
+            }
+            for attr in attributes
+        ]
+    
+    def get_original_attributes(self, obj):
+        """Get manually entered original attribute values."""
+        values = ProductAttributeValue.objects.filter(product=obj)
+        return {val.attribute_name: val.original_value for val in values}

+ 45 - 5
attr_extraction/urls.py

@@ -1,13 +1,53 @@
-# ==================== urls.py ====================
+# # ==================== urls.py ====================
+# from django.urls import path
+# from .views import ExtractProductAttributesView,ProductTypeListView, ProductTypeAttributesView, 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'),
+#     path('products/attributes/', ProductTypeAttributesView.as_view(), name='product-upload-excel'),
+#     path('product-types/', ProductTypeListView.as_view(), name='product-types-list'),
+# ]
+
+
+
+
+# urls.py
 from django.urls import path
-from .views import ExtractProductAttributesView,ProductTypeListView, ProductTypeAttributesView, ProductAttributesUploadView, BatchExtractProductAttributesView, ProductListView, ProductUploadExcelView
+from .views import (
+    ExtractProductAttributesView,
+    ProductTypeListView,
+    ProductTypeAttributesView,
+    ProductAttributesUploadView,
+    BatchExtractProductAttributesView,
+    ProductListView,
+    ProductUploadExcelView,
+    ProductAttributeValueView,
+    BulkProductAttributeValueView,
+    # ProductAttributeValueUploadExcelView,
+    ProductListWithAttributesView
+)
 
 urlpatterns = [
+    # Existing endpoints
     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/', ProductListView.as_view(), name='product-list'),
     path('products/upload-excel/', ProductUploadExcelView.as_view(), name='product-upload-excel'),
-    path('products/upload-attributes/', ProductAttributesUploadView.as_view(), name='product-upload-excel'),
-    path('products/attributes/', ProductTypeAttributesView.as_view(), name='product-upload-excel'),
+    path('products/upload-attributes/', ProductAttributesUploadView.as_view(), name='product-upload-attributes'),
+    path('products/attributes/', ProductTypeAttributesView.as_view(), name='product-type-attributes'),
     path('product-types/', ProductTypeListView.as_view(), name='product-types-list'),
+    
+    # New endpoints for original attribute values
+    path('products/with-attributes/', ProductListWithAttributesView.as_view(), name='products-with-attributes'),
+    path('attribute-values/', ProductAttributeValueView.as_view(), name='attribute-values'),
+    path('attribute-values/bulk/', BulkProductAttributeValueView.as_view(), name='attribute-values-bulk'),
+    # path('attribute-values/upload-excel/', ProductAttributeValueUploadExcelView.as_view(), name='attribute-values-upload'),
 ]
+
+
+
+

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 522 - 324
attr_extraction/views.py


BIN
db.sqlite3


Vissa filer visades inte eftersom för många filer har ändrats