Django 在视图中将表单添加到表单集中

Django add forms to formset in a view

我遇到了设计问题。

想象一个订单模型和material模型,

class Material(models.Model):
    material_code = models.CharField(max_length=40)
    standard_price = models.DecimalField()

class Order(models.Model):
    customer = models.ForeignKey(Customer)


class OrderItems(models.Model):
    order = models.ForeignKey(Order)
    material = models.ForeignKey(Material)
    price = models.DecimalField()

在我的订单详细信息视图中,我使用 inlineformset_factory(Order, OrderItems)

填充订单项

我想要的行为如下:

如果用户想添加更多订单项,我想将用户重定向到 material 列表页面,用户选择一个或多个 material 并确认,然后我将他重定向到订单详细信息视图有新添加的项目。

我正在考虑这些工作,比如带有中间页面的 django 管理操作。

在向订单中添加新的 orderitems 之前,我还想从 material standard_price 设置 orderitems 价格,这意味着我想在将其添加到 orderitems 之前修改 formsets 值。


我想问的问题是,有没有更简单的方法来实现这一点,似乎将表单集数据存储到会话并用新项目重新填充表单集并不容易。我会考虑另一种解决这个问题的方法。

顺便说一句,我不想​​要 js 解决方案,想象一下我的订单模型上的一个字段,grandtotal,我可以计算项目总金额,使用 js 解决方案我可能必须用 js 做计算逻辑,用户添加一个项目并更改价格,然后我用 js 进行总计计算。这是我想避免的。

您可以通过 "Adding dynamic fields" 将其简化为您的订单详细信息表单。

当用户单击 "Add material" 按钮时,将向表单添加一个新字段(例如 <select> 包含材料列表的字段)。

link 将帮助您完成任务。

根据您提供的描述,我没有找到 formsets 的用例。

您只需要一个 material 目录页,其中列出了 material。每个 material 都可以添加到当前购物车,这是通过 Ajax 调用 url 来完成的,该 url 传递 material 的 PK,因此视图对于 Ajax 调用可以创建购物车并将 material 添加到购物车。

最后您需要一个 OrderDetail,您需要对当前在用户购物车中的所有 material 进行 forloop。

你可以先完全在数据库中实现,为Cart定义关系模型,其实就是你已经实现的Orderclass

然后你可以添加一个缓存层来限制 writes/deletes/updates 到数据库,使用 django 会话(考虑到你不在你的数据库中存储会话,这有一个性能提升!)

所以总而言之,您可能需要的是(我使用购物车的概念,暗示用户只能有一个有效订单,如果您的要求不同,它可以很容易地更改为您想要的提供了您的订单模型):

数据模型:

class Cart:
     user = 1to1(User, related_name='cart') # Can be a FK if you want several active orders
     is_approved = Boolean # To tell if the order is considered Over or is still open
     created_at = DateTimeField
     ...

class Material:
     orders = M2M(Cart, through=CartItem)
     ...

class CartItem:
     cart = FK(Cart)
     material = FK(Material)
     ...

观看次数:

def list_materials(request):
    returns_rendered_template_with(materials=Material.objects.all())

#Ajax method, called via Post, you probably need a way to also delete, or edit (number of materials to order ?)
def add_material_to_cart(request, material_id):
    cart = Cart.objects.get_or_create(user=request.user)
    material = Material.objects.get(pk=material_id)
    CartItem(material=material, cart=cart).save()

def order_detail_view(request):
    cart = user.cart
    cart_items = CartItems.objects.filter(cart=cart)
    returns_rendered_template_with(cart_items=cart_items)

模板:

material_list.html

....
{% for item in materials %}
       {% show material info, such as price, availability, ... %}
       <button data-pk={{item.pk}}, ...> to call add_material_to_cart </button>
{% endfor %}

order_detail.html

....
{% for item in cart_items %}
       {% show each cart_item.material and its information + whatever you need %}
{% endfor %}

这是你可以实现的最基本的形式,我明白了,你想要的。
您可以将这些视图中的几个合并在一起,您可以实现一个“完全在会话中”的解决方案,而不需要 Cart 和 CartItem 模型,只是最终订单被持久化到我不知道,比尔模型?订单历史 ?随心所欲

如果我理解你的意图是正确的,你想创建某种购物车,而不想为尚未下达的订单创建数据库条目。

我的建议是创建一个 Cart 模型和一个 CartItem 模型来存储有关购物车中当前有哪些商品的信息。 当客户下订单时,您使用购物车及其商品中相应的 OrderItem 实例创建一个新的 Order 实例,并保留该实例。

CartCartItem 可以是存储在数据库中的 Django 模型,也可以是普通的 Python 类 并将它们序列化以存储在会话中。

将它们存储在数据库中可能更容易,但很可能会生成比基于会话的解决方案更多的数据库查询。这是否是一个问题取决于您的服务器容量和预期负载。这种方法在 Oscar 中实现,这是一个 Django 的电子商务框架。