작성
·
352
·
수정됨
0
선생님 안녕하세요.
태그 클릭 시 관련 게시글만 보여주는 파트까지는 잘 실행되었습니다.
그 후, 게시글 클릭 시 detail 로 넘어가는 부분에서 오류가 발생했습니다. 혹시 오타가 있는가 해서 복사-붙여넣기를 해봤지만 계속 오류가 발생합니다.Page not found (404)
Request Method:GETRequest URL:http://localhost:8000/blog/post/undefined/
Using the URLconf defined in mysite.urls
, Django tried these URL patterns, in this order:
admin/
[name='home']
blog/ post/list/ [name='post_list']
blog/ post/<int:pk>/ [name='post_detail']
api/
The current path, blog/post/undefined/
, didn’t match any of these.
You’re seeing this error because you have DEBUG = True
in your Django settings file. Change that to False
, and Django will display a standard 404 page.
답변 2
0
독자님. vuetify v3 사용하는 거 맞죠?
지금 올려주신 소스는 v2 버전입니다. 섹션 10. 소스 다운로드에 대한 설명이 있으니,
그 설명에서 VueDjangoVite 프로젝트 소스를 활용하세요.
해보시고 다시 질문 바랍니다.
0
안녕하세요. 독자님.
Vuetify v3 을 사용중이시죠? v-data-table 이 동작해서 포스트 목록은 잘 나오고 있는 상태이지요?
그렇다면 제공된 소스에서 ~/components/PostList.vue 의 serverPage() 메소드가 정확하게 코딩되어 있고 잘 동작하는지 확인 부탁합니다. 즉 테이블에서 행을 클릭하면 해당 게시글의 detail 화면으로 넘어가야 합니다.
이게 잘 되면 다시 한번 질문 올려주시기 바랍니다.
강의 처음부터 복습했는데 다시 이 부분에서 안됩니다. 테이블에서 행을 클릭하면 같은 오류 떠요.
serverPage(item) {
console.log("serverPage()...", item);
location.href = `/blog/post/${item.id}/`;
},
이 부분의 item.id 를 인식 못하는거 같은데 왜 그런지 잘 모르겠습니다.
<template>
<v-container>
<v-data-table
:headers="headers"
:items="posts"
:sort-by="name"
class="elevation-1"
:Items-per-page="5"
@click:row="serverPage"
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Post List
<span v-if="tagname" class="body-1 font-italic ml-3">(with {{ tagname }} tagged)</span>
</v-toolbar-title>
<v-divider class="mx-4" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ props }">
<v-btn color="primary" dark class="mb-2" v-bind="props">
New Post
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="text-h5">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.name" label="Dessert name"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.calories" label="Calories"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.fat" label="Fat (g)"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.carbs" label="Carbs (g)"></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="editedItem.protein" label="Protein (g)"></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue-darken-1" variant="text" @click="close">
Cancel
</v-btn>
<v-btn color="blue-darken-1" variant="text" @click="save">
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialogDelete" max-width="500px">
<v-card>
<v-card-title class="text-h5">Are you sure you want to delete this item?</v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue-darken-1" variant="text" @click="closeDelete">Cancel</v-btn>
<v-btn color="blue-darken-1" variant="text" @click="deleteItemConfirm">OK</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:[`item.actions`]="{ item }">
<v-icon size="small" class="me-2" @click="editItem(item.raw)">
mdi-pencil
</v-icon>
<v-icon size="small" @click="deleteItem(item.raw)"> mdi-delete </v-icon>
</template>
<template v-slot:no-data>
<v-btn color="primary" @click="fetchPostList"> Reset </v-btn>
</template>
</v-data-table>
</v-container>
</template>
<script>
import axios from "axios";
export default {
data: () => ({
dialog: false,
dialogDelete: false,
headers: [
{
title: 'ID',
align: 'start',
sortable: false,
key: 'id',
},
{ title: '제 목', key: 'title' },
{ title: '요 약', key: 'description' },
{ title: '수정일', key: 'modify_dt' },
{ title: '작성자', key: 'protein' },
{ title: 'Actions', key: 'actions', sortable: false },
],
posts: [],
tagname: '',
editedIndex: -1,
editedItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0,
},
defaultItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0,
},
}),
computed: {
formTitle() {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
},
},
watch: {
dialog(val) {
val || this.close()
},
dialogDelete(val) {
val || this.closeDelete()
},
},
created() {
const params = new URL(location).searchParams;
this.tagname = params.get('tagname');
this.fetchPostList()
},
methods: {
fetchPostList() {
console.log("fetchPostList()...", this.tagname);
let getUrl = '';
if (this.tagname) getUrl = `/api/post/list/?tagname=${this.tagname}`;
else getUrl = '/api/post/list/'
axios.get(getUrl)
.then(res => {
console.log("POST LIST GET RES", res);
this.posts = res.data;
})
.catch(err => {
console.log("POST LIST GET ERR.RESPONSE", err.response);
alert(err.response.status + ' ' + err.response.statusText);
});
},
serverPage(item) {
console.log("serverPage()...", item);
location.href = `/blog/post/${item.id}/`;
},
editItem(item) {
this.editedIndex = this.posts.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem(item) {
this.editedIndex = this.posts.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialogDelete = true
},
deleteItemConfirm() {
this.posts.splice(this.editedIndex, 1)
this.closeDelete()
},
close() {
this.dialog = false
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
})
},
closeDelete() {
this.dialogDelete = false
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
})
},
save() {
if (this.editedIndex > -1) {
Object.assign(this.posts[this.editedIndex], this.editedItem)
} else {
this.posts.push(this.editedItem)
}
this.close()
},
},
}
</script>
<style scoped>
.v-data-table >>> tbody > tr {
cursor: pointer;
}
</style>
와 드디어 됐어요.
정말 감사합니다.