I am currently building a LMS where the admin can upload multiple images to a lesson. I am having some issues rendering these images with vue.js.
In my models.py I have a Photos model which uses a foreignkey to the lesson model. In the admin I can add the images but in the html the images appear as an empty list with the photo id number e.g [4] In the console I can see the photos array with the length of photos in the lesson object but I cant seem to attach it to the frontend.
Here is the vue template:
<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>
The 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)
And my 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')
Any help with this would be really appreciated!