【问题标题】:Django inheritance obtain typeof child from base classDjango继承从基类获取typeof子
【发布时间】:2016-11-22 18:13:33
【问题描述】:

我有以下三个模型:

from model_utils.managers import InheritanceManager

class Product(models.Model):
    name = models.CharField(max_length=50, blank=False, verbose_name="Type here name",)

class Pub(Product):
    product = models.OneToOneField(Product, parent_link=True, )
    seating_capacity = models.IntegerField(null=False, verbose_name="Seating capacity of the Pub",)

class Restaurant(Product):
   product = models.OneToOneField(Product, parent_link=True, )
   food_speciality = MultiSelectField(choices = MY_CHOICES)

我已经实现了 django-cart 并将 Product 作为我的产品模型。我将所有产品退回到我的前端。这基本上将仅具有产品特定属性的产品对象发送到前端,因此很难区分哪个产品是 Pub 哪个是 Restaurant。

如何在后端处理这个问题?有什么方法可以提取/发送产品类型吗?

这就是我的视图:

@api_view(('GET',))
def show(request):
    cart = Cart(request.session)
    products = cart.products
    serializer = ProductSerializer(products, many=True)
    return Response(serializer.data)

它返回例如:

[{"id":1,"name":"Shreyas","price":"45000.00000","avg_user_rating":"4.50000","city":1},{"id":4,"name":"Phadake","price":"350.00000","avg_user_rating":"5.00000","city":2}] 

序列化器:

class ProductSerializer(serializers.ModelSerializer):
    category = serializers.ReadOnlyField()
    class Meta:
            model = Product
            fields = '__all__'

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    选项 1

    将带有verbose_nameMeta 类添加到您的模型中:

    class Pub(Product):
        product = models.OneToOneField(Product, parent_link=True, )
        seating_capacity = models.IntegerField(null=False, verbose_name="Seating capacity of the Pub",)
    
        class Meta:
            verbose_name = 'Pub'
    
    class Restaurant(Product):
        product = models.OneToOneField(Product, parent_link=True, )
        food_speciality = MultiSelectField(choices = MY_CHOICES)
    
        class Meta:
            verbose_name = 'Restaurant'
    

    将这些行添加到ProductSerializer:

    category = serializers.SerializerMethodField()
    
    def get_category(self, obj):
        return obj._meta.verbose_name
    

    选项 2

    或者,您可以为每个模型添加property

    class Pub(Product):
        product = models.OneToOneField(Product, parent_link=True, )
        seating_capacity = models.IntegerField(null=False, verbose_name="Seating capacity of the Pub",)
    
        @property
        def category(self):
            return 'Pub'
    
    class Restaurant(Product):
        product = models.OneToOneField(Product, parent_link=True, )
        food_speciality = MultiSelectField(choices = MY_CHOICES)
    
        @property
        def category(self):
            return 'Restaurant'
    

    然后将这一行添加到ProductSerializer:

    category = serializers.ReadOnlyField()
    

    选项 3

    当然,如果您不想在模型中添加 Meta 或属性,您也可以选择这样做:

    def get_category(self, obj):
        return obj.__class__.__name__
    

    但是你会受到限制,每个类别都等于类的名称,这可能是个问题。

    【讨论】:

    • 非常感谢!我会试试的。
    • 我选择了选项 2 并更新了我的序列化程序,但它返回了相同的响应。我已经用序列化程序代码更新了我的问题。你能看一下吗?
    • 从序列化程序的 Meta 中删除 fields = '__all__'。你记得给你的每个模型添加一个category 属性吗?
    • 是的,我在 Pub and Rest 中添加了类别。当我用 ['category'] 替换 'all' 时,它会给出 [{},{}]
    • 我知道发生了什么。当您使用cart.products 获取产品时,您的产品似乎总是Product 的实例。我看到你用你的会话数据实例化了一个Cart 对象,可能是从哪些产品实例化的。确保使用正确的类实例化这些产品。例如,您可以在序列化程序的方法中检查obj 的类。关于fields,完全不需要定义,从Meta中移除即可。
    猜你喜欢
    • 1970-01-01
    • 2016-09-02
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-05
    • 2018-03-07
    • 2019-09-01
    相关资源
    最近更新 更多