【问题标题】:Render images with Vue.js and Django使用 Vue.js 和 Django 渲染图像
【发布时间】:2022-01-26 03:20:38
【问题描述】:

我目前正在构建一个 LMS,管理员可以在其中将多个图像上传到课程中。我在使用 vue.js 渲染这些图像时遇到了一些问题。

在我的 models.py 中,我有一个 Photos 模型,它使用课程模型的外键。在管理员中,我可以添加图像,但在 html 中,图像显示为带有照片 ID 号的空列表,例如 [4] 在控制台中,我可以在课程对象中看到带有照片长度的照片数组,但我似乎看不到将其附加到前端。

这里是vue模板:

                    <template>
    <div class="courses">
        <div class="hero is-light">
            <div class="hero-body has-text-centered">
                <h1 class="title">{{ course.title }}</h1>
            </div>
        </div>

        <section class="section">
            <div class="container">
                <div class="columns content">
                    <div class="column is-2">
                        <h2>Table of contents</h2>

                        <ul>
                            <li
                                v-for="lesson in lessons"
                                v-bind:key="lesson.id"
                            >
                                <a @click="setActiveLesson(lesson)">{{ lesson.title }}</a>
                            </li>
                        </ul>
                    </div>

                    <div class="column is-10">
                        <template v-if="$store.state.user.isAuthenticated">
                            <template v-if="activeLesson">
                                <h2>{{ activeLesson.title }}</h2>
                                
                                {{ activeLesson.long_description }}
                                      {{ activeLesson.photos }}

                                <hr>

                                <article 
                                    class="media box"
                                    v-for="comment in comments"
                                    v-bind:key="comment.id"
                                >
                                    <div class="media-content">
                                        <div class="content">
                                            <p>
                                                <strong>{{ comment.name }}</strong> {{ comment.created_at }}<br>
                                                {{ comment.content }}
                                            </p>
                                        </div>
                                    </div>
                                </article>

                                <form v-on:submit.prevent="submitComment()">
                                    <div class="field">
                                        <label class="label">Name</label>
                                        <div class="control">
                                            <input type="text" class="input" v-model="comment.name">
                                        </div>
                                    </div>

                                    <div class="field">
                                        <label class="label">Content</label>
                                        <div class="control">
                                            <textarea class="textarea" v-model="comment.content"></textarea>
                                        </div>
                                    </div>

                                    <div 
                                        class="notification is-danger"
                                        v-for="error in errors"
                                        v-bind:key="error"
                                    >
                                        {{ error }}
                                    </div>

                                    <div class="field">
                                        <div class="control">
                                            <button class="button is-link">Submit</button>
                                        </div>
                                    </div>
                                </form>
                            </template>

                            <template v-else>
                                {{ course.long_description }}
                            </template>
                        </template>

                        <template v-else>
                            <h2>Restricted access</h2>
                            
                            <p>You need to have an account to continue!</p>
                        </template>
                    </div>
                </div>
            </div>
        </section>
    </div>
</template>

<script>
import axios from 'axios'

export default {
    data() {
        return {
            course: {},
            lessons: [],
            comments: [],
            activeLesson: null,
            errors: [],
            comment: {
                name: '',
                content: ''
            }
          
        } 
    }, 
    

    async mounted() {
        console.log('mounted')
        const slug = this.$route.params.slug

        await axios
            .get(`/api/v1/courses/${slug}/`)
            .then(response => {
                console.log(response.data)
                this.course = response.data.course
                this.lessons = response.data.lessons
            })
        document.title = this.course.title + ' | Relate'

    },
    methods: {
        submitComment() {
            console.log('submitComment')
            this.errors = []
            if (this.comment.name === '') {
                this.errors.push('The name must be filled out')
            }
            if (this.comment.content === '') {
                this.errors.push('The content must be filled out')
            }
            if (!this.errors.length) {
                axios
                    .post(`/api/v1/courses/${this.course.slug}/${this.activeLesson.slug}/`, this.comment)
                    .then(response => {
                        this.comment.name = ''
                        this.comment.content = ''
                        this.comments.push(response.data)
                    })
                    .catch(error => {
                        console.log(error)
                    })
            }
        },
        setActiveLesson(lesson) {
            this.activeLesson = lesson
            this.getComments() 
        },
        getComments() {
            axios
                .get(`/api/v1/courses/${this.course.slug}/${this.activeLesson.slug}/get-comments/`)
                .then(response => {
                    console.log(response.data)
                    this.comments = response.data
                })
        }
    }
}
</script>

models.py:

class Lesson(models.Model):
    DRAFT = 'draft'
    PUBLISHED = 'published'

    CHOICES_STATUS = (
        (DRAFT, 'Draft'),
        (PUBLISHED, 'Published')
    )

    ARTICLE = 'article'
    QUIZ = 'quiz'

    CHOICES_LESSON_TYPE = (
        (ARTICLE, 'Article'),
        (QUIZ, 'Quiz')
    )

    course = models.ForeignKey(Course, related_name='lessons', on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    slug = models.SlugField()
    short_description = models.TextField(blank=True, null=True)
    long_description = models.TextField(blank=True, null=True)
    status = models.CharField(max_length=20, choices=CHOICES_STATUS, default=PUBLISHED)
    lesson_type = models.CharField(max_length=20, choices=CHOICES_LESSON_TYPE, default=ARTICLE)


    def __str__(self):
        return self.title

class Photo(models.Model):
    lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, related_name='photos')
    photo = models.ImageField(upload_to ='lesson_images')

    # resizing the image, you can change parameters like size and quality.
    def save(self, *args, **kwargs):
       super(Photo, self).save(*args, **kwargs)
       img = Image.open(self.photo.path)
       if img.height > 1125 or img.width > 1125:
           img.thumbnail((1125,1125))
       img.save(self.photo.path,quality=70,optimize=True) 

还有我的 serializers.py:

class LessonListSerializer(serializers.ModelSerializer):
    # photo = PhotoSerializers(read_only=True, many=True)
    class Meta:
        model = Lesson
        fields = ('id', 'title', 'slug', 'short_description', 'long_description', 'photos')

对此的任何帮助将不胜感激!

【问题讨论】:

    标签: javascript python django vue.js django-rest-framework


    【解决方案1】:

    似乎您需要在 Vue 模板中添加一个 &lt;img /&gt; 标记,然后遍历照片(应该是一个数组),将 :src 绑定到照片 url 字符串,并将 :key 绑定到唯一的id 或索引。

    类似

    <div class="column is-10">
        <template v-if="$store.state.user.isAuthenticated">
            <template v-if="activeLesson">
                <h2>{{ activeLesson.title }}</h2>
                
                {{ activeLesson.long_description }}
                <img v-for="(photo, index) in activeLesson.photos" :src="photo.url" :key="index" />
    
                <hr>
    

    【讨论】:

    • 好的,刚试了。不幸的是,它没有用 - 索引指的是什么?
    • 索引是图像数组中的当前索引,我不认为您的数据以正确的格式输出图像,它需要是图像的链接。所以 :src="my-url.com/lesson-photo-1" 如果它是一些 BLOB 或 db 引用,它不会工作,因为它只是 HTML。
    • 我将图像保存在 django media/uploads/lesson_images 文件夹中?
    • 那么有没有办法以编程方式从 activeLesson 对象中的数据中迭代这些 url?所以 activelesson.url 应该给你例如:'./mylocalfolder/lesson-image-1.jpg' 你需要输出图像的源引用,无论它是托管 URL 还是本地。 stackoverflow.com/questions/45116796/…
    • 即使我在 :src 中修补文件路径,我仍然没有显示任何图像。这是因为我使用的是 DRF 吗?
    猜你喜欢
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2014-01-25
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    相关资源
    最近更新 更多