admin管理员组

文章数量:1291218

I am using Django as a backend and I am trying to pass some data into a Vue table ponent that I made. I set it up using this tutorial The ponent is showing up fine while using a webpack. I am trying to set the data to a javascript constant and then pass it into the ponent. The data does not appear to be passing through. Here is how my scripts are laid out.

index.html

{% block content %}
<script>
  const gridData = {{json_data|safe}};
  console.log(gridData)
</script>

    <div id="app">
        <table_ponent
        v-bind:tableData=this.gridData
        >
        </table_ponent>

    </div>  
{% end block %}

myComponent.vue script seciton

export default {
  name: 'table_ponent',
    props: {
    tableData: Array
  },
  data() {
      return {

      }
  },
  ponents: {
    Grid,
    ButtonModal
  },
  created(){
    console.log(this.tableData)
  },
}

When I look at the console, it is not showing any data. It just says undefined.

view.py

class CurrentClassroomView(LoginRequiredMixin, CreateView):
    template_name = 'home/index.html'

    def get(self, request, *args, **kwargs):
        db_data = list(myData.objects.all().values())
        my_json_data = json.dumps(db_data)
        return render(request, self.template_name, {'json_data':my_json_data})  

I am getting this in the console that I am not sure what that means and why it is making everything lowercase even though I'm passing it with upper case letters.

[Vue tip]: Prop "griddata" is passed to ponent <Anonymous>, but the declared prop name is "gridData". Note that HTML attributes are case-insensitive and camelCased props need to use their kebab-case equivalents when using in-DOM templates. You should probably use "grid-data" instead of "GridData".
tip @ vue.js:639
extractPropsFromVNodeData @ vue.js:2294
createComponent @ vue.js:3233
_createElement @ vue.js:3427
createElement @ vue.js:3359
vm._c @ vue.js:3496
eval @ VM1553:3
Vue._render @ vue.js:3550
updateComponent @ vue.js:4066
get @ vue.js:4477
Watcher @ vue.js:4466
mountComponent @ vue.js:4073
Vue.$mount @ vue.js:9043
Vue.$mount @ vue.js:11943
Vue._init @ vue.js:5011
Vue @ vue.js:5077
eval @ index.js:14
./assets/js/index.js @ app.js:409
__webpack_require__ @ app.js:20
(anonymous) @ app.js:84
(anonymous) @ app.js:87

Any help on this would be greatly appreciated. I am not sure where I am going wrong

I am using Django as a backend and I am trying to pass some data into a Vue table ponent that I made. I set it up using this tutorial The ponent is showing up fine while using a webpack. I am trying to set the data to a javascript constant and then pass it into the ponent. The data does not appear to be passing through. Here is how my scripts are laid out.

index.html

{% block content %}
<script>
  const gridData = {{json_data|safe}};
  console.log(gridData)
</script>

    <div id="app">
        <table_ponent
        v-bind:tableData=this.gridData
        >
        </table_ponent>

    </div>  
{% end block %}

myComponent.vue script seciton

export default {
  name: 'table_ponent',
    props: {
    tableData: Array
  },
  data() {
      return {

      }
  },
  ponents: {
    Grid,
    ButtonModal
  },
  created(){
    console.log(this.tableData)
  },
}

When I look at the console, it is not showing any data. It just says undefined.

view.py

class CurrentClassroomView(LoginRequiredMixin, CreateView):
    template_name = 'home/index.html'

    def get(self, request, *args, **kwargs):
        db_data = list(myData.objects.all().values())
        my_json_data = json.dumps(db_data)
        return render(request, self.template_name, {'json_data':my_json_data})  

I am getting this in the console that I am not sure what that means and why it is making everything lowercase even though I'm passing it with upper case letters.

[Vue tip]: Prop "griddata" is passed to ponent <Anonymous>, but the declared prop name is "gridData". Note that HTML attributes are case-insensitive and camelCased props need to use their kebab-case equivalents when using in-DOM templates. You should probably use "grid-data" instead of "GridData".
tip @ vue.js:639
extractPropsFromVNodeData @ vue.js:2294
createComponent @ vue.js:3233
_createElement @ vue.js:3427
createElement @ vue.js:3359
vm._c @ vue.js:3496
eval @ VM1553:3
Vue._render @ vue.js:3550
updateComponent @ vue.js:4066
get @ vue.js:4477
Watcher @ vue.js:4466
mountComponent @ vue.js:4073
Vue.$mount @ vue.js:9043
Vue.$mount @ vue.js:11943
Vue._init @ vue.js:5011
Vue @ vue.js:5077
eval @ index.js:14
./assets/js/index.js @ app.js:409
__webpack_require__ @ app.js:20
(anonymous) @ app.js:84
(anonymous) @ app.js:87

Any help on this would be greatly appreciated. I am not sure where I am going wrong

Share Improve this question asked Feb 28, 2020 at 23:15 laxerlaxer 76013 silver badges44 bronze badges 1
  • I'm also using Django as backend and vuejs as frontend. My advice is the following : use an API and query it from vuejs. You can use graphene-django (the graphql implementation for django) to build an API alongside with apollo to query the graphql endpoint (that's what I'm actually doing) or DRF (Django Rest Framework). Otherwise I don't know how to directly pass data from django to vuejs. – lbris Commented Feb 29, 2020 at 1:09
Add a ment  | 

3 Answers 3

Reset to default 10

When you set gridData and try to bind it to a Vue ponent it is not working because they have different contexts. When you dealing with Vue ponents you can only access data defined inside the Vue instance. Additionally, {{json_data|safe}} is vulnerable to XSS-type attacks.

However, it is very easy to safely pass data from Django to a Vue ponent, we just have to use the json_script filter and load the data in Vue's mounted hook.

In views.py just pass the list to the template, no need to use json.dumps():

class CurrentClassroomView(LoginRequiredMixin, CreateView):
    template_name = 'home/index.html'

    def get(self, request, *args, **kwargs):
        db_data = list(myData.objects.all().values())
        return render(request, self.template_name, {'json_data':db_data}) 

In index.html, we will use the json_script template tag to create a JSON formatted representation of json_data variable:

{% block content %}
{{ json_data|json_script:"json_data" }}

<div id="app">
    <table_ponent></table_ponent>
</div>  
{% end block %}

This will create a <script> block, e.g.:

<script id="json_data" type="application/json">{"hello": "world"}</script>

And finally, in myComponent.vue, we load, JSON-decode and set the data in the mounted hook:

export default {
  data() {
      return {
          tableData
      }
  },
  ponents: {
    Grid,
    ButtonModal
  },
  mounted() {
    this.tableData = JSON.parse(document.getElementById('json_data').textContent)
  },
}

I think you could just pass Django's server-side props straight into a child ponent that uses it. Mine's set up like this:

{% extends "ExpenseTracker/layout.html" %}
{% load static %}

{% block content %}
<div id="transactionlabeling_view"
>
 <transactions-table 
 :cached_items = "{{transactions}}"
 :account_types = "{{account_types}}"
 ></transactions-table>
</div>
{% endblock content %}

where there's a Vue ponent that is mounted on "#transactionlabeling_view". There, I imported the child ponent transactions-table where I passed on the server side props from Django view ({{transactions}} & {{account_types}}) into props inside transactions-table ponent (:cached_items & :account_types):

props:{
    cached_items:null,
    account_types:null
},

It's convenient that you don't have to JSON.parse those two props, vue got that job done for you. But you do need to use JSON.dump on {{transactions}} & {{account_types}} before passing it as context in the html. works like a charm, I use vue 3.2.6 and Django 4.1.6 and have vue installed inside django.

If you're using Vue 3 with SFC (single file ponent) syntax, the .provide() method (on createApp()) works really well for this purpose. In the Django template, pass your variables from the template (via Django context).

I'm using a hidden (and disabled) <input element within the div where the app will be mounted. I'm not sure if this is best practice, but it seems more secure to me...

What I like most about this approach is that the mounted ponent replaces the data-provider DOM element (the hidden input)!

<!-- This is the Django template file -->
<!-- vue_ponent_block.html -->
<div name="vue-ponent-mount-point">
  <input
    disabled
    type="hidden"
    data-url="{{ url_from_django_context }}"
    data-text="{{ link_text_from_django_context }}"
  />
</div>
<!-- This is the TS/JS bundle, it'll need to be included somewhere as well (after the above template content) -->
<script src="path/to/your/dist/folder/my_piled_script.js"></script>
// This is a TS (can be JS) file piled into the Django app
import { createApp } from "vue";
import MyLinkComponent from "./MyLinkComponent.vue";

const mountPoints: [HTMLElement] = document.querySelectorAll('[name="vue-ponent-mount-point"]')

mountPoints.forEach((mountPoint: HTMLElement) => {
  const children: HTMLCollection = mountPoint.children
  const dataInput: HTMLElement = children[0] as HTMLInputElement
  const dataset: Object = dataInput.dataset
  createApp(MyLinkComponent)
    .provide('dataset', dataset)
    .mount(mountPoint);
})

Then, in the ponent's .vue file, I'll use inject() to grab the data from the provider (using the same dataset key).

<template>
  <MyLinkComponent
    :href="dataset['url']"
  >{{ dataset['text'] }}</MyLinkComponent>
</template>

<script setup lang="ts">
import { inject } from 'vue'
const dataset = inject('dataset')
</script>

本文标签: javascriptPass Django Data into Vue componentStack Overflow