如何将 vue.js 与 django 集成?

Posted

技术标签:

【中文标题】如何将 vue.js 与 django 集成?【英文标题】:how to integrate vue.js with django? 【发布时间】:2019-10-25 11:24:14 【问题描述】:

这是带有 vue.js 的单页应用程序,它进行了一些简单的计算,我试图在 django 中实现这个计算,但它没有给我想要的结果。 在这里,我在 vue.js 中动态创建了数组,这只是完美地显示了产品的图像,而不是 product.nameproduct.sell_price 以及 @click.prevent="addToCart(product)"this 函数不起作用?我该如何解决?

vue.js

   <script src="% static 'js/vue.js' %"></script>

   <script type="text/javascript" src="% static '/js/vue-resource.js' %"></script>
    <script>

 new Vue(
    el: '#posApp',
    
    data: 
        total: 0,
        discount: 0,
        products: [
            % for product in products %
                
                    "id": product.id,
                    "name": "product.name",
                    "image": "/media/product.image",
                    "price": product.sell_price
                ,
              % endfor %

        ],
        cart: [],
        search: ""
    ,
    methods: 

        addToCart: function(product)

            var found = false;
            for (var i = 0; i < this.cart.length; i++)
                if (this.cart[i].id === product.id)
                    this.cart[i].quantity++;
                    found = true;
                
            
            if (!found) 
                this.cart.push(
                    id: product.id,
                    name: product.name,
                    sell_price: product.sell_price,
                    quantity: 1
                );
            

            this.total += product.sell_price;
        ,
        inc: function(item)
            item.quantity++;
            this.total += item.sell_price;
        ,
        dec: function(item)
            item.quantity--;
            this.total -= item.sell_price;
            if (item.quantity <= 0)
                var i = this.cart.indexOf(item);
                this.cart.splice(i, 1);
            
        ,
        removeFromCart: function(item)
            this.cart.splice(this.cart.indexOf(item), 1);
            this.total = this.total - (item.sell_price * item.quantity);
        ,
        clearCart: function()
            this.cart = [];
            this.total = 0;
            this.discount = 0;
        ,
        payment: function()
            this.cart = [];
            this.total = 0;
            this.discount = 0;
            alert('Transaction Completed');
        
    ,
    computed: 
        filteredProducts()
            // var lowerTitle = product.title.toLowerCase();
            return this.products.filter((product) => 
                return product.name.toLowerCase().match(this.search);
            );
        
    
);
</script>

html

 <div class="col-md-3" v-for="product in filteredProducts" :key="product.id"> <!-- Inner-Col .// -->
                  <a href="#" @click.prevent="addToCart(product)">
                    <div class="box box-default pos-product-card"> <!-- /.box -->
                      <img class="card-img-top img-responsive" :src="product.image" >
                      <div class="box-body"> <!-- /.box-body -->
                        <h4 class="box-title"> product.name </h4>
                        <!-- <p class="box-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> -->
                        <button class="btn btn-info"><i class="fas fa-shopping-cart"></i></button>
                      </div> <!-- /.box-body -->
                    </div> <!-- /.box -->
                  </a>
                </div>
% for category in categories %
            <div class="tab-pane fade" id="category-category.id">

                <div class="row"> <!-- Inner-Row .// -->
                    % for product in category.product_set.all %
                   <div class="col-md-3" v-for="product in filteredProducts" :key="product.id"> <!-- Inner-Col .// -->
                  <a href="#" @click.prevent="addToCart(product)">
                    <div class="box box-default pos-product-card"> <!-- /.box -->
                      <img class="card-img-top img-responsive" :src="product.image" >
                      <div class="box-body"> <!-- /.box-body -->
                        <h4 class="box-title"> product.name </h4>
                        <!-- <p class="box-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p> -->
                        <button class="btn btn-info"><i class="fas fa-shopping-cart"></i></button>
                      </div> <!-- /.box-body -->
                    </div> <!-- /.box -->
                  </a>
                </div>
                    % endfor %
     <table class="table table-hover text-center">
                                  <!-- <thead class="thead-dark"> -->
                                    <tr>
                                      <th>Item</th>
                                      <th>Quantity</th>
                                      <th>Rate</th>
                                      <th>Subtotal</th>
                                      <th>&nbsp;</th>
                                    </tr>
                                  <!-- </thead> -->
                                      <tr v-for="item in cart" :key="item.id">

                    <td><a href="#"> item.name </a></td>
                    <td><button class="btn btn-flat btn-xs btn-info p-1 mx-1" @click="inc(item.id)">+</button>[[ item.quantity ]]<button class="btn btn-flat p-1 mx-1 btn-xs btn-info" @click="dec(item.id)">-</button></td>
                    <td><span class="text-muted"> item.sell_price </span> </td>
                    <td>Rs  item.sell_price * item.quantity </td>
                    <td><button class="btn btn-xs btn-outline-primary" @click="removeFromCart(item)"><i class="fas fa-trash-alt"></i></button></td>
                  </tr>
                                  </table>
                                </div>
                                <div class="no-item-msg" v-if="cart.length === 0">No items in the cart.</div>
                              </div>
         <table class="table">
                                    <tr>
                      <td>Total Items</td>
                      <td> cart.length </td>
                    </tr>
                    <tr>
                      <td>Total Amount</td>
                      <td> total </td>
                    </tr>
                    <tr>
                      <td><span class="height-control">Discount (In Amount)</span></td>
                      <td><input type="number" v-model="discount" class="form-control"></td>
                    </tr>
                    <tr class="bg-dark">
                      <td>TO PAY</td>
                      <td> total-discount </td>
                    </tr>

【问题讨论】:

dynamic django variables 是什么意思?它们是如何“动态”的? 【参考方案1】:

有几点需要你考虑:

    似乎您的 html 中有语法冲突,因为 Django 和 Vue.js 使用相同的 来放置变量。但是,由于 Django 将在 Vue 之前处理您的 html,它将替换

    &lt;h4 class="box-title"&gt; product.name &lt;/h4&gt;

    通过它将在上下文中找到的内容(服务器端的 Django tepmlate 上下文)。您可以在浏览器中查看源代码或您的页面,您可能会在该行看到:

    &lt;h4 class="box-title"&gt;&lt;/h4&gt;

    因为它不会找到 python product 变量(实际上你的意思是 js(vue) 变量)。

    解决方案:使用另一个 Vue 分隔符。见https://vuejs.org/v2/api/#delimiters。例如,在 Vue 中使用 [[ 而不是 :您的 Vue 实例 delimiters: ['[[', ']]'], 的一个选项并将该行(以及其他您指 Vue 变量的地方)更改为

    &lt;h4 class="box-title"&gt;[[ product.name ]]&lt;/h4&gt;

    在 Vue 数据中你有 not product.sell_price 变量,就像你做的时候一样

  % for product in products %
     
      "id": product.id,
      "name": "product.name",
      "image": "/media/product.image",
      "price": product.sell_price
      ,
  % endfor %

在 Vue 中你将拥有 product.price,而不是 product.sell_price。或者你必须 将上面的行更改为"sell_price": product.sell_price

    很快您将面临item 变量的麻烦。正如您在 django 上下文中拥有 item 一样,而不是在 Vue 数据中。您应该像为 products 所做的那样将项目添加到 Vue 数据中。

    一般考虑将您的方法从混合 django 模板和 Vue 代码更改为:

    Django 向 Vue 传递数据 Vue 生成所有 html 并执行您的 js 功能

    使用Django Rest framework(https://www.django-rest-framework.org/)提供rest API 仅在前端使用 Vue,从服务器加载数据并通过 REST 调用将更改放入服务器(例如使用 axios

祝你好运。

【讨论】:

我按照您的建议通过添加分隔符解决了这个问题,现在考虑到类别过滤器,我遇到了一些小问题。属于某些类别 ID 的产品没有正确显示。之前没有 addtoCart(product)功能,它现在工作我添加了这个链接,现在它不工作了。有什么解决方案吗?谢谢你的帮助 DRF (django-rest-framework) 不是在 Django 中实现 rest API 所必需的 - 您可以使用更轻(且侵入性更小的)包或手动执行(rest API 它只是 django 视图提供 json 而不是提供 html....) 关于 categoriesproducts 再次你对 Vue 数据和 Django 上下文感到困惑。 django 循环中的product 将从category.product_set.all 获取,但在该循环内,Vue 将从filteredProducts 获取product - 不是来自django(不是来自类别)。 (注意:我看不到你对源文件的最后更改,如果有的话 - 最好在你的源中提供 github gist 左右)。

以上是关于如何将 vue.js 与 django 集成?的主要内容,如果未能解决你的问题,请参考以下文章

vue.js 和 Laravel - 我们如何将 vue js 与 laravel 集成?

如何将 PHP smarty 模板与 Vue.js 集成?

如何将我的 Vue js SPA 部署到我的 Django 服务器中?

将 Stylelint 与 Vue.js 集成

将 Laravel 与 Vue js 集成

将 peerjs 与 nuxtjs (vue.js) 集成时出错