0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

画像アップロード「Uploadthing」を使って、Nuxt3×Djnagoアプリから画像を削除する

Posted at

完成イメージ

画像をアップロードして...

image.png

こんな感じに画像がアップロードされる。

image.png

DELETEボタンを押すとメッセージが表示されて....

image.png

画面から画像が削除される。

image.png

uploadthingのダッシュボードにからも削除される

image.png

以上のサンプルを作っていきます。

ディレクトリ構造

.
└── NuxtDjangoProject/
    ├── backend/
    │   ├── adminuser
    │   ├── api/
    │   │   ├── migrations/
    │   │   │   └── 0001_initial.py
    │   │   ├── serializer.py
    │   │   ├── urls.py
    │   │   └── views.py
    │   └── todoproject/
    │       ├── settings.py
    │       └── urls.py
    └── frontend/
        ├── components/
        │   ├── footer/
        │   │   └── footer.vue
        │   └── navbar/
        │       └── navbar.vue
        ├── pages/
        │   ├── adminUsers/
        │   │   ├── login/
        │   │   │   └── login.vue
        │   │   ├── registration/
        │   │   │   └── registration.vue
        │   │   ├── updateProfile/
        │   │   │   └── updateProfile.vue
        │   │   └── uploadImageFile/
        │   │       └── uploadImageFile.vue
        │   ├── login/
        │   │   └── login.vue
        │   ├── registration/
        │   │   └── registration.vue
        │   └── index.vue
        ├── .env
        ├── server/
        │   ├── api/
        │   │   └── uploadthing/
        │   │       └── delete.ts
        │   └── uploadthing.ts
        ├── app.vue
        ├── nuxtconfig.ts/
        │   └── package.json
        └── tsxconfig.json

サーバ側の処理

サーバ側の処理は下記のとおりです。

frontend/server/api/uploadthing/delete.ts
import { UTApi } from "uploadthing/server";
import { z } from 'zod'

const utapi = new UTApi({
    apiKey:process.env.UPLOADTHING_TOKEN
});

export default defineEventHandler(async (event)=>{
    try{
        const body = await readBody(event);
        const { key } = z.object({key:z.string()}).parse(body);

        if(!process.env.UPLOADTHING_TOKEN){
            console.log('Please set UPLOADTHING_TOKEN.');
            throw new Error('UPLOADTHING_SECRET is not set.');
        }

        const response = await utapi.deleteFiles([key]);
        console.log('Uploadthing delete response:',response);

        if(response.success){
            return {success:true};
        }else{
            console.log('Uploadthing delete failed:',response.error);
            return {success:false,error:response.error};
        }
    }catch(error:any){
        console.error('サーバーエラー:', error);
        return { success: false, error: error.message };
    }
});

フロント側の処理

フロント側の処理は下記のとおりです。

frontend/pages/adminUsers/uploadImageFile/uploadImageFile.vue
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { ref } from 'vue'
import { useFetch } from 'nuxt/app'

const router = useRouter();
const alert = (msg: string) => {
  window.alert(msg);
  
};

/** Method for deleting image */
const fileRef = ref<File | null>(null);// Type is set at File or null
const imageKey = ref<string>('');

const setImageInfo = (data:any)=>{
  imageKey.value = file[0].key;
}

const clickImageDelete = async()=>{
  if(!imageKey.value){
    alert('Please select targe image.');
    return;
  }

  const { data,error } = await useFetch('/api/uploadthing/delete',{
    method:'POST',
    body:{
      key:imageKey.value,
    },
  });

  if(error.value){
    console.log('Fail delete image,',error.value);
    alert('Faile delete image.');
    return;
  }

  if(data.value?.success){
    alert('Success to delete target image.');
    fileRef.value = null;
    imageKey.value = '';
  }else{
    alert('Fail to delete.');
  }
}
</script>

<template>
  <div>
    <UploadButton
      :config="{
        endpoint: 'imageUploader',
        onClientUploadComplete: (file) => {
          if(file && file.length > 0){
            console.log('file:', file[0]);//Debug file object.
            console.log('file[0].key:', file[0].key); // Debug file[0].key.
            console.log('Convert String type for file[0].key is :', String(file[0].key)); // Convert type of string.
            fileRef = file[0].url;// Debug file[0].url.
            imageKey = String(file[0].key);
            console.log('imageKey.key:', imageKey); // 追加
            console.log('fileRef after upload:', fileRef); // 追加
          }                    
          alert('Upload complete');
        },
        onUploadError: (error) => {
          console.error(error, error.cause);
          alert('Upload failed');
        },
      }"
    />
    <UploadDropzone
      :config="{
        endpoint: 'imageUploader',
        onClientUploadComplete: (file) => {
          console.log('uploaded', file);
          console.log('uploaded', file[0].url);
          console.log('uploaded', file[0].key);
          fileRef = file[0].url;// Debug file[0].url.
          imageKey = String(file[0].key);
          alert('Upload complete');
        },
        onUploadError: (error) => {
          console.error(error, error.cause);
          alert('Upload failed');
        },
      }"
    />
    <!-- Image thumbnail Area -->
    <div v-if="imageKey" class="flex items-center justify-center">
      <v-avatar size="x-large">
        <v-img
        :src="fileRef"
      ></v-img>
      </v-avatar>
    </div>
    <!-- Image key Area -->
    <div>
      <input type="hidden" :value="imageKey"/>
    </div>
    <!-- Image thumbnail button Area -->
    <div v-if="imageKey" class="flex items-center justify-center mt-8">
      <v-btn
        type="button"
        color="success"
        @click="clickImageDelete"
      >
        Delete
      </v-btn>
    </div>
  </div>
</template>

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?