【问题标题】:Django add forms to formset in a viewDjango 在视图中将表单添加到表单集
【发布时间】:2017-01-04 06:20:30
【问题描述】:

我陷入了一个设计问题。

想象一个订单模型和材料模型,

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) 填充订单项

我想要的行为如下:

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

我正在考虑使用这些功能,例如带有中间页面的 django 管理操作。

在将新的订单项添加到订单之前,我还想从材料标准价格设置订单项价格,这意味着我想在添加到订单项之前修改表单集的值。


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

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

【问题讨论】:

  • 总问题很容易避免。永远不要从客户那里接受你想要控制的东西。所以“加入购物车”js 调用只提交商品 ID 和数量。它接收新的购物车总数(在服务器上计算)并呈现更新的迷你购物车。问题解决了。

标签: django formset


【解决方案1】:

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

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

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

您可以先在数据库中完全实现它,为 Cart 定义关系模型,这实际上是您已经实现的 Order 类。

然后您可以使用 django session 添加一个缓存层来限制对数据库的写入/删除/更新(考虑到您不在数据库中存储会话,这会提高性能!)

总而言之,您可能需要的是(我使用购物车的概念,暗示用户只能拥有一个活动订单,如果您的要求不同,则可以轻松更改为您所拥有的随您的 Order 模型提供):

数据模型:

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 模型,只需将最终订单持久化到我不知道的 Bill 模型中?订单历史 ?随心所欲。

【讨论】:

  • A +1 花时间,你就快到了。只有摆脱材料。它不是必需的,并引入了微妙的错误。购物车中的所有商品都与 CartItem 中的多对一完美关联。引入 Material 允许多个购物车项目与多个购物车相关联,而 CartItem 本身不允许这样做,直到您添加 null 属性然后事情变得时髦。
  • @Melvyn 如果他摆脱 Material,他将无法拥有一个公开的 material 列表 页面。这样,他可以列出材料供用户选择,在选择时,创建实际上只属于该用户的相应CartItem。同时,恕我直言,为用户列出 Material 比列出 CartItem 更具可读性。 CartItems 将在 CartDetail 视图中列出,恕我直言。
  • CartItem 的实例也只能与单个购物车相关联。所以每个用户都有一个购物车,里面可能有几个 CartItems。在结帐时,他可以刷新当前的 CartItems (checked_out=True),因此用户面临着一个全新的购物车。材料用于向用户展示可用的内容,Cart 和 CartItem 用于结帐和计费。
  • 您忽略了产品。产品是您称为“物料清单”的目录。无需将产品与订单关联。如果还没有订单,那你要列出什么?想象一下现实生活中的超市:您将产品放入购物车,然后将它们放在收银台并付款,然后您就收到了订单。是的,购物车中的产品仅在 单个 购物车中,而不是同时在多个购物车中。但是一个单个购物车可以包含多个产品。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    您可以通过“添加动态字段”到您的订单详细信息表单来简化此操作。

    当用户单击“添加材料”按钮时,将在表单中添加一个新字段(例如带有材料列表的 &lt;select&gt; 字段)。

    link 将帮助您完成任务。

    【讨论】:

    • 我没明白,这如何回答我的问题。你能详细说明一下吗?
    猜你喜欢
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    相关资源
    最近更新 更多