【问题标题】:django ecommerce product db designdjango电子商务产品数据库设计
【发布时间】:2021-11-01 17:18:38
【问题描述】:

我为我的 django 电子商务项目设计了一个数据库,但它有一些问题,目标是 这个设计是为了有不同规格的产品,比如一个手机有它自己的属性,一个电视也有, 这是我的models.py:

'''

from django.db import models
    from mptt.models import MPTTModel, TreeForeignKey
    from django.shortcuts import reverse
    from model_utils import FieldTracker
    from . import uploaders


    class Category(MPTTModel):
        name = models.CharField(max_length=50, unique=True)
        parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, 
        related_name='children')
        slug = models.SlugField(max_length=75, unique=True)
        tracker = FieldTracker(fields=['name'])

        class MPTTMeta:
            order_insertion_by = ['name']

        def __str__(self):
            category_names = [self.name]
            node = self
            while node.parent:
                node = node.parent
                category_names.append(node.name)
            return ' / '.join(category_names[::-1])

        def get_absolute_url(self):
            return reverse('product_by_category', args=(self.slug,))


    class ProductType(models.Model):
        name = models.CharField(max_length=50, unique=True)

        def __str__(self):
            return self.name


    class ProductSpecifications(models.Model):
        name = models.CharField(max_length=50)
        product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE, 
        related_name='specifications')

        class Meta:
            unique_together = ('name', 'product_type')

        def __str__(self):
            return self.name


    class Product(models.Model):
        name = models.CharField(max_length=100, unique=True)
        product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE, 
        related_name='products')
        category = models.ForeignKey(Category, on_delete=models.CASCADE, 
        related_name='products')
        price = models.PositiveBigIntegerField()
        discount_price = models.PositiveBigIntegerField(null=True, blank=True)
        description = models.TextField(null=True, blank=True)
        image = models.ImageField(upload_to=uploaders.product_img_uploader)
        slug = models.SlugField(max_length=150, unique=True)
        tracker = FieldTracker(fields=['slug', 'name', 'product_type'])

        def __str__(self):
            return self.name

        def set_discount(self, percentage):
            self.discount_price = self.price * (1 - percentage)
            self.save()

        @property
        def is_discounted(self):
            return bool(self.discount_price)

        def remove_discount(self):
            self.discount_price = None
            self.save()


    class ProductSpecificationValue(models.Model):
        specification = models.ForeignKey(ProductSpecifications, on_delete=models.CASCADE)
        product = models.ForeignKey(Product, on_delete=models.CASCADE, 
        related_name='specifications')
        value = models.CharField(max_length=75, null=True, blank=True)

        def __str__(self):
            return ''

        class Meta:
            unique_together = ('specification', 'product')
'''

还有 admin.py:

'''

    from django.contrib import admin
    from django.http import HttpResponseRedirect
    from mptt.admin import MPTTModelAdmin
    from .models import *
    from .forms import ProductSpecForm


    @admin.register(Category)
    class CategoryAdmin(MPTTModelAdmin):
        readonly_fields = ('slug',)


    class SpecificationInline(admin.TabularInline):
        model = ProductSpecifications
        extra = 2


    @admin.register(ProductType)
    class ProductTypeAdmin(admin.ModelAdmin):
        inlines = (SpecificationInline,)


    class SpecificationValueInline(admin.TabularInline):
        model = ProductSpecificationValue
    # form = ProductSpecForm
    # fields = ('specification', 'value')
    # readonly_fields = ('specification',)
    # 
    # def has_add_permission(self, request, obj):
    #     return False
    # 
    # def has_delete_permission(self, request, obj=None):
    #     return False


    @admin.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        inlines = (SpecificationValueInline,)
        readonly_fields = ('slug',)

        # def response_post_save_add(self, request, obj):
        #     return HttpResponseRedirect(
        #         reverse("admin:%s_%s_change" % (self.model._meta.app_label, 
        #         self.model._meta.model_name), args=(obj.id,)))

'''
当您想添加或更改产品时,问题出在产品管理面板中,我希望 SpecificationValueInline 表单中的规范选择框只显示与产品类型相关的规范,而不是数据库中的所有规范,我在管理员中评论的行。带有一些信号和表格的py是我解决这个问题的方法我不知道这是否是最好的帮助我! 信号.py:

'''

from django.dispatch import receiver
    from django.db.models.signals import pre_save, post_save
    from .models import Category, Product, ProductSpecificationValue, ProductSpecifications


    @receiver(pre_save, sender=Product)
    @receiver(pre_save, sender=Category)
    def initialize_slug(sender, instance, *args, **kwargs):
        if (not instance.slug) or (instance.tracker.has_changed('name')):
            instance.slug = instance.name.replace(' ', '_')


    @receiver(post_save, sender=Product)
    def initialize_specifications(sender, instance, created, **kwargs):
        if created:
            product_type = instance.product_type
            for specification in product_type.specifications.all():
                ProductSpecificationValue.objects.create(product=instance, 
                specification=specification)
        elif instance.tracker.has_changed('product_type'):
            ProductSpecificationValue.objects.filter(product=instance).delete()
            product_type = instance.product_type
            for specification in product_type.specifications.all():
                ProductSpecificationValue.objects.create(product=instance, 
                specification=specification)



    @receiver(post_save, sender=ProductSpecifications)
    def add_new_specs_to_related_products(sender, instance, created, **kwargs):
        if created:
            product_type = instance.product_type
            for product in product_type.products.all():
                ProductSpecificationValue.objects.create(specification=instance, 
                product=product)

''' 表格.py: '''

from django import forms
    from django.forms import ModelChoiceField

    from .models import ProductSpecificationValue, Product


    class ProductSpecForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            if hasattr(self.instance, 'product'):
                self.fields['specification'] = ModelChoiceField(
                    queryset=self.instance.product.product_type.specifications.all())

        class Meta:
            model = ProductSpecificationValue
            fields = ('specification', 'value')

'''

【问题讨论】:

    标签: python django database e-commerce


    【解决方案1】:

    您可以在 SpecificationValueInline 中使用formfield_for_foreignkey

    class SpecificationValueInline(admin.TabularInline):
        model = ProductSpecificationValue
    
        def formfield_for_foreignkey(self, db_field, request, **kwargs):
            if db_field.name == "specification":
                product_id = request.resolver_match.kwargs.get('object_id')
                productType = Product.objects.get(id = product_id).product_type
                kwargs["queryset"] = ProductSpecification.objects.filter(product_type=productType)
            return super().formfield_for_foreignkey(db_field, request, **kwargs)
    

    【讨论】:

      【解决方案2】:

      mohsen ma 的回答很有用,我做了一些更改,它变得更好,但我仍然怀疑这是否足够或最佳实践,如果用户更改产品类型,他/她应该留在更改页面上以填写规范 idk 如何: '''

      @receiver(post_save, sender=Product)
      def sync_specs_with_type(sender, instance, created, **kwargs):
          if created or instance.tracker.has_changed('product_type'):
              if not created:
                  instance.specifications.all().delete()
              for spec in instance.product_type.specifications.all():
                  ProductSpecificationValue.objects.create(product=instance, specification=spec)
      
      class SpecificationValueInline(admin.TabularInline):
          model = ProductSpecificationValue
          extra = 0
      
          def formfield_for_foreignkey(self, db_field, request, **kwargs):
              product_id = request.resolver_match.kwargs.get('object_id')
              if product_id and db_field.name == "specification":
                  product_type = Product.objects.get(id=product_id).product_type
                  kwargs["queryset"] = ProductSpecifications.objects.filter(product_type=product_type)
              return super().formfield_for_foreignkey(db_field, request, **kwargs)
      
      
      @admin.register(Product)
      class ProductAdmin(admin.ModelAdmin):
          readonly_fields = ('slug',)
          inlines = (SpecificationValueInline,)
      
          def response_post_save_add(self, request, obj):
              messages.add_message(request, messages.INFO, 'set you product specifications')
              return HttpResponseRedirect(
                  reverse("admin:%s_%s_change" % (self.model._meta.app_label, self.model._meta.model_name), args=(obj.id,)))
      
          def get_inlines(self, request, obj):
              if obj:
                  return super().get_inlines(request, obj)
              return ()
      

      '''

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-28
        • 1970-01-01
        • 1970-01-01
        • 2018-09-03
        • 2019-02-22
        • 2019-08-24
        • 2020-06-08
        • 1970-01-01
        相关资源
        最近更新 更多