【问题标题】:how to relate models effectively using Django Rest Framework如何使用 Django Rest Framework 有效地关联模型
【发布时间】:2020-02-03 17:51:10
【问题描述】:

我正在尝试创建一个应用程序来保存商店的帐户。每次将发票上传到系统时,它必须在另一个名为“products”的表中创建产品,但如果产品已经存在,则只需更新价格和数量。

每张发票可以有多个产品

  1. 我应该如何提出表之间的关系?一对多、一对一、多对多?

  2. 是否有任何方法可以在每张发票上创建产品列表来表示这种关系?一个供应商可以带来不止一种产品。

  3. 有没有一种方法可以在产品表中创建记录而不创建重复项?如果在输入新发票时更新了库存中的价格和数量,则无需多次拥有相同的产品。

例如,要输入的发票有以下信息:

  • 号码
  • 列表项
  • 提供者
  • 产品:(列表)
    • 产品一
    • 产品b
    • 产品c
  • 总计
  • 日期

如果产品 A 存在,发票必须更新库存中的价格和数量。

如果产品 C 不存在,发票必须创建产品。

到目前为止,这就是我所拥有的:

invoice/models.py

from django.db import models

from product.models import Product
from sales.models import PaymentMethod


class Supplyer(models.Model):
    """
    Proveedor de servicios o productos
    """

    rif = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    phone = models.CharField(max_length=255)
    email = models.EmailField()

    def __str__(self):
        return '{} - {}'.format(self.name, self.rif)


class Invoice(models.Model):
    """
    Clase que controla las facturas ingresadas al sistema
    """

    ref = models.CharField(max_length=255)
    supplyer = models.OneToOneField(Supplyer, on_delete=models.CASCADE)
    items = models.ManyToManyField(Product)
    total = models.DecimalField(max_digits=14, decimal_places=2)
    paymnet_method = models.OneToOneField(PaymentMethod, on_delete=models.CASCADE)
    date = models.DateField(auto_now_add=True, auto_now=False)

    def __str__(self):
        return '{} - {} - {}'.format(self.supplyer, self.date, self.ref)

invoice/serializers.py

from rest_framework.serializers import ModelSerializer
from invoice.models import Supplyer, Invoice
from stock.models import Product
from stock.serializers import ProductSerializer


class SupplyerSerializer(ModelSerializer):
    """
    Clase que controla los proveedores de productos o servicios
    """

    class Meta:
        model = Supplyer
        fields = ('rif', 'name', 'phone', 'email')


class InvoiceSerializer(ModelSerializer):
    """
    Clase que controla las facturas de proveedores.

    Esta clase tiene un metodo crear propio para poder crear productos cuando
    se carga la factura, y si el producto ya existe, debe actualizar el costo
    del producto en el inventario
    """

    # Llamada al serializador de productos
    product_serializer = ProductSerializer(many=True)

    # Llamada al serializador de proveedores
    supplyer_serializer = SupplyerSerializer()

    class Meta:
        model = Invoice
        fields = ('ref', 'supplyer_serializer', 'product_serializer', 'total', 'payment_method', 'date')

    def create(self, validated_data):
        """
        Este metodo sobre escribe el metodo de crear instancia por defecto del
        serializador, esto nos permite crear un producto y actualizar el
        precio al momento de cargar la factura al sistema.

        self: llamada al metodo
        validated_data: Datos validados por el serializador
        """

        # lista de productos o servicios en la factura
        products_obj = validated_data.pop('items')

        # Cargar la factura a la base de datos
        invoice = Invoice.objects.create(**validated_data)

        # Iterar por la lista de productos de la factura
        for product in products_obj:
            Product.objects.create(products_obj)

        return invoice

    def update(self, instance, validated_data):
        """
        Este metodo actualiza las facturas y productos asociados a ella

        self: llamada al metodo
        instance: instancia u objeto a modificar
        validated_data: datos validados por el serializador
        """

        # Se obtienen los datos de los productos en la factura
        products_obj = validated_data.pop('items')
        products = (instance.product_serializer).all()
        products = list(products)

        # Se selecciona la factura y se actualizan los datos
        instance.ref = validated_data.get('ref', instance.ref)
        instance.supplyer = validated_data.get('supplyer', instance.supplyer)
        instance.total = validated_data.get('total', instance.total)
        instance.payment_method = validated_data.get('payment_method', instance.payment_method)

        # Iterar pro la lista de productos
        for product_data in products_obj:
            # Dentro del bucle se atualizan los datos de los productos
            product = products.pop(0)
            product.name = product_data.get('name', product.name)
            product.description = product_data.get('description', product.description)
            product.price = product_data.get('price', product.price)
            product.save()

        return instance

stock/models.py

from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=12, decimal_places=2)


class Stock(models.Model):
    item    = models.OneToOneField(Product, on_delete='CACADE')
    package = models.CharField(max_length=255)
    unity   = models.IntegerField()
    date    = models.DateTimeField(auto_now=True)
    value   = models.DecimalField(max_digits=12, decimal_places=2)
    cost   = models.DecimalField(max_digits=12, decimal_places=2)
    qty     = models.IntegerField()

    def __str__(self):
        return '{}'.format(self.date)

【问题讨论】:

    标签: python django python-3.x serialization django-rest-framework


    【解决方案1】:

    您似乎需要另一个模型来表示发票的行项目,包括数量和价格。例如,如果发票 1 包含 50 公斤砖和 100 公斤水泥,那么发票 2 包含 20 公斤砖和 20 公斤水泥,您要如何跟踪这两个记录?

    在您当前的模型中,产品“积木”可以链接到发票 1 和发票 2,但没有地方可以存储每张发票上列出的不同数量的积木。

    如果您将发票行项目存储在单独的模型中,它将具有发票的外键字段、产品的外键字段以及数量和价格字段。当您有特定发票时,您可以follow the relationship backwards 获取其订单项。

    【讨论】:

    • 在这种情况下,我将创建一个具有重复值的表,假设一张发票输入 100 个块,另一张发票输入 50 个,那么该表中将有 2 条记录,第一个有 100 个块,而第二个有 50 块。我的问题是发票表应该与产品表有什么样的关系,以便在创建发票时更新产品而不是创建新产品,我不知道这是否正确,或者如果我应该创建一个包含重复产品的表并针对该表更新销售表
    • 我认为我不太了解您的问题,尤其是关于“以便在创建发票时更新产品而不是创建新产品”的部分。这是来自另一个问题的inventory database structure diagram。除了它的“product”表和“order”表之外,它还有一个“product_order”表,我的意思是表示发票的行项目。
    • 在这种情况下,它应该是多对多的关系,一张发票有多个产品,并通过该发票计算产品的数量和价值。但是如何防止发票创建同一篇文章的多个记录?请原谅我的英语,但这不是我的语言。 (我应该发送数据库图吗?)@krubo
    • 当然,如果你有结构图,你可以将它添加到你的问题中。另外,也许您可​​以解释一个具体的示例,例如,如果用户输入 {example},系统应该如何响应?
    猜你喜欢
    • 1970-01-01
    • 2021-12-17
    • 2022-06-14
    • 2014-09-17
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 2018-11-11
    • 2021-12-31
    相关资源
    最近更新 更多