জাজানো ফাইলফিল্ড মুছুন


97

আমি জ্যাঙ্গোতে একটি ওয়েব অ্যাপ তৈরি করছি। আমার কাছে এমন একটি মডেল রয়েছে যা কোনও ফাইল আপলোড করে তবে আমি এটি মুছতে পারি না। আমার কোডটি এখানে:

class Song(models.Model):
    name = models.CharField(blank=True, max_length=100)
    author = models.ForeignKey(User, to_field='id', related_name="id_user2")
    song = models.FileField(upload_to='/songs/')
    image = models.ImageField(upload_to='/pictures/', blank=True)
    date_upload = models.DateField(auto_now_add=True)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.song.storage, self.song.path
        # Delete the model before the file
        super(Song, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)

তারপরে, "পাইথন ম্যানেজ.পি শেল" এ আমি এটি করি:

song = Song.objects.get(pk=1)
song.delete()

এটি ডাটাবেস থেকে মুছে ফেলা হয় তবে সার্ভারে থাকা ফাইলটি নয়। আমি আর কি চেষ্টা করতে পারি?

ধন্যবাদ!


সরাসরি ডিফল্ট_স্টোরেজ ব্যবহার সম্পর্কে কী? docs.djangoproject.com/en/dev/topics/files
এমজিপি

উত্তর:


146

জ্যাঙ্গো ১.৩ এর আগে, আপনি সংশ্লিষ্ট মডেল উদাহরণটি মুছে ফেললে ফাইলটি স্বয়ংক্রিয়ভাবে ফাইল সিস্টেম থেকে মুছে ফেলা হয়েছিল। আপনি সম্ভবত একটি নতুন জ্যাঙ্গো সংস্করণ ব্যবহার করছেন, সুতরাং আপনাকে নিজেরাই ফাইল সিস্টেম থেকে ফাইল মুছে ফেলা প্রয়োগ করতে হবে।

আপনি এটি কয়েকটি উপায়ে করতে পারেন যার মধ্যে একটি হ'ল একটি pre_deleteবা post_deleteসিগন্যাল using

উদাহরণ

আমার পছন্দের পদ্ধতিটি বর্তমানে সংকেত post_deleteএবং pre_saveসংকেতগুলির মিশ্রণ যা এটি তৈরি করে যাতে অপরিবর্তিত ফাইলগুলি মুছে ফেলা হয় যখনই সম্পর্কিত মডেলগুলি মুছে ফেলা হয় বা তাদের ফাইল পরিবর্তন করা হয়।

একটি কাল্পনিক MediaFileমডেলের উপর ভিত্তি করে :

import os
import uuid

from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _


class MediaFile(models.Model):
    file = models.FileField(_("file"),
        upload_to=lambda instance, filename: str(uuid.uuid4()))


# These two auto-delete files from filesystem when they are unneeded:

@receiver(models.signals.post_delete, sender=MediaFile)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """
    Deletes file from filesystem
    when corresponding `MediaFile` object is deleted.
    """
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)

@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """
    Deletes old file from filesystem
    when corresponding `MediaFile` object is updated
    with new file.
    """
    if not instance.pk:
        return False

    try:
        old_file = MediaFile.objects.get(pk=instance.pk).file
    except MediaFile.DoesNotExist:
        return False

    new_file = instance.file
    if not old_file == new_file:
        if os.path.isfile(old_file.path):
            os.remove(old_file.path)
  • এজ কেস: যদি আপনার অ্যাপ্লিকেশন কোনও নতুন ফাইল আপলোড করে এবং কল না করেই নতুন ফাইলটিতে মডেল উদাহরণটি দেখায় save()(যেমন: বাল্ক আপডেট করে QuerySet), পুরানো ফাইলটি পড়ে থাকবে কারণ সংকেতগুলি চালিত হবে না। আপনি যদি প্রচলিত ফাইল হ্যান্ডলিং পদ্ধতি ব্যবহার করেন তবে এটি ঘটে না।
  • আমি মনে করি আমি যে অ্যাপ্লিকেশন তৈরি করেছি তার একটির এই কোডটি উত্পাদন রয়েছে তবে তা সত্ত্বেও আপনার নিজের ঝুঁকিতে ব্যবহার করুন।
  • কোডিং শৈলী: এই উদাহরণটি fileক্ষেত্রের নাম হিসাবে ব্যবহার করে , যা কোনও ভাল শৈলী নয় কারণ এটি বিল্ট-ইন fileঅবজেক্ট শনাক্তকরণকারীর সাথে সংঘর্ষে লিপ্ত হয় ।

আরো দেখুন

  • FieldFile.delete()জ্যাঙ্গো ১.১১ মডেলের ক্ষেত্রের রেফারেন্সে (নোট করুন যে এটি FieldFileক্লাসটি বর্ণনা করে , তবে আপনি .delete()সরাসরি মাঠে কল করতে পারেন : FileFieldউদাহরণস্বরূপ সংশ্লিষ্ট FieldFileউদাহরণের প্রক্সিগুলি এবং আপনি এর পদ্ধতিগুলি অ্যাক্সেস করে যেমন তারা ক্ষেত্রের)

    মনে রাখবেন যে কোনও মডেল মুছে ফেলা হলে সম্পর্কিত ফাইলগুলি মোছা হয় না। আপনার যদি অনাথ ফাইলগুলি পরিষ্কার করার প্রয়োজন হয় তবে আপনাকে এটি নিজে পরিচালনা করতে হবে (উদাহরণস্বরূপ, একটি কাস্টম ম্যানেজমেন্ট কমান্ড যা ম্যানুয়ালি চালানো যেতে পারে বা যেমন ক্রোনের মাধ্যমে পর্যায়ক্রমে চালানোর জন্য নির্ধারিত হবে)।

  • কেন জ্যাঙ্গো ফাইলগুলি স্বয়ংক্রিয়ভাবে মুছবে না: জাজানো 1.3 এর জন্য প্রকাশিত নোটগুলিতে প্রবেশ

    পূর্ববর্তী জ্যাঙ্গো সংস্করণগুলিতে, যখন কোনও মডেল উদাহরণটি FileFieldমুছে ফেলা হয়েছিল, FileFieldতখন এটি ব্যাকএন্ড স্টোরেজ থেকে ফাইলটি মুছতে নিজেই নেবে। এটি একই ফাইলকে বিভিন্ন মডেলের রোলড-ব্যাক লেনদেন এবং ক্ষেত্রগুলি সহ একাধিক ডেটা-লোকসান দৃশ্যের জন্য দরজা খুলেছে। জ্যাঙ্গো ১.৩-এ, যখন কোনও মডেল মুছে ফেলা হয় FileFieldতার delete()পদ্ধতিটি বলা হবে না। আপনার যদি অনাথ ফাইলগুলি পরিষ্কার করার প্রয়োজন হয় তবে আপনাকে এটি নিজে পরিচালনা করতে হবে (উদাহরণস্বরূপ, একটি কাস্টম ম্যানেজমেন্ট কমান্ড যা ম্যানুয়ালি চালানো যেতে পারে বা যেমন ক্রোনের মাধ্যমে পর্যায়ক্রমে চালানোর জন্য নির্ধারিত হবে)।

  • pre_deleteশুধুমাত্র একটি সংকেত ব্যবহারের উদাহরণ


4
হ্যাঁ, তবে উপযুক্ত চেকগুলি নিশ্চিত করে নিন। (আমাকে একটি সেকেন্ড দিন, আমি প্রকৃত সিস্টেমে ব্যবহৃত কোডটি পোস্ট করব))
আন্তন স্ট্রোগনফ

7
এটি সম্ভবত ব্যবহার করা আরও ভাল instance.song.delete(save=False), যেহেতু এটি সঠিক জ্যাঙ্গো স্টোরেজ ইঞ্জিন ব্যবহার করে।
এডুয়ার্ডো

4
আজকাল বিরল যে আমি কোডটি অনুলিপি করছি আমি সরাসরি এসও থেকে নিজেকে লিখতে পারতাম না এবং এটি সীমিত পরিবর্তন নিয়ে কাজ করে। চমত্কার সহায়তা, ধন্যবাদ!
জিজেস্টেইন

এটিতে একটি ত্রুটি পাওয়া গেছে যেখানে উদাহরণটি উপস্থিত থাকলে, তবে কোনও চিত্র আগে সংরক্ষণ করা হয়নি, তবে os.path.isfile(old_file.path)ব্যর্থ হয়েছে কারণ old_file.pathত্রুটি উত্থাপন করে (কোনও ফাইল ক্ষেত্রের সাথে সম্পর্কিত নয়)। আমি if old_file:কল করার ঠিক আগে যোগ করে এটি ঠিক করেছি os.path.isfile()
তিন_ আনারস

@ থ্রি_পাইন্যাপলসটি বোঝায়। এটি হতে পারে যে ফাইল ক্ষেত্রের ন্যূনাল সীমাবদ্ধতা বাইপাস করা হয়েছিল বা কোনও পর্যায়ে প্রস্থান করা হয়নি, এই ক্ষেত্রে কিছু বস্তু এটি খালি রাখতে পারে।
অ্যান্টন স্ট্রোগনফ অফ

79

ব্যবহার করে দেখুন জ্যাঙ্গো-পরিষ্করণ , এটি স্বয়ংক্রিয়ভাবে FileField ডিলিট পদ্ধতি যখন আপনি মডেল অপসারণ ডাকে।

pip install django-cleanup

সেটিংস.পি

INSTALLED_APPS = (
     ...
    'django_cleanup', # should go after your apps
)

দুর্দান্ত, এটি ডিফল্টরূপে ফাইলফিল্ডে যুক্ত করা দরকার, ধন্যবাদ!
মেগাজো

এটি ফাইল আপলোড করার সাথে সাথে মুছে ফেলা হচ্ছে
চিরাগ সোনি

কি দারুন. আমি চেষ্টা করছিলাম যেন এটি না ঘটে এবং আমি কেন বুঝতে পারছিলাম না figure কেউ এই বছর আগে ইনস্টল করা হয়েছে এবং এটি সম্পর্কে ভুলে গেছেন। ধন্যবাদ
ryan28561

4
সুতরাং, কেন জ্যাঙ্গো প্রথম স্থানে ফাইলফিল্ড মুছে ফাংশন সরিয়ে ফেলল?
হা-নিউল

আপনি কিংবদন্তি !!
মার্লোনজড

33

.deleteনীচে জাজানো> = 1.10 এর সাথে দেখানো ফাইল ফিল্ডের কলিং পদ্ধতির সাথে আপনি ফাইল সিস্টেম থেকে ফাইলটি মুছতে পারেন :

obj = Song.objects.get(pk=1)
obj.song.delete()

7
সাধারণ এবং সহজ কাজ হিসাবে গ্রহণযোগ্য উত্তর হওয়া উচিত।
নিকোলে শিন্দারভ

15

মডেলটির মুছে ফাংশনটি ফাইলের জন্য উপস্থিত রয়েছে কিনা তা পরীক্ষা করার জন্য এটি সরানো যেতে পারে এবং সুপার ফাংশনটি কল করার আগে এটি মুছুন।

import os

class Excel(models.Model):
    upload_file = models.FileField(upload_to='/excels/', blank =True)   
    uploaded_on = models.DateTimeField(editable=False)


    def delete(self,*args,**kwargs):
        if os.path.isfile(self.upload_file.path):
            os.remove(self.upload_file.path)

        super(Excel, self).delete(*args,**kwargs)

8
সাবধান থাকুন যে কলিং queryset.delete()এই সমাধানটি দিয়ে ফাইলগুলি পরিষ্কার করবে না। আপনার ক্যোরিসেটের মাধ্যমে পুনরুক্তি করতে হবে এবং .delete()প্রতিটি বস্তুকে কল করতে হবে।
স্কট উডাল

আমি জাজানোতে নতুন am এটি ভাল, তবে কী যদি মডেলটি মুছে ফেলা পদ্ধতিটিকে ছাড়িয়ে যাওয়া কোনও বিমূর্ত শ্রেণীর কাছ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয়, তবে এটি কি বিমূর্ত শ্রেণীর থেকে ওভাররাইড হবে না? সংকেত ব্যবহার করা আমার কাছে আরও ভাল প্রদর্শিত হয়
টিপান

8

জাজানো 2.x সমাধান:

জ্যাঙ্গো 2 এ ফাইল মোছার বিষয়টি পরিচালনা করা খুব সহজ । আমি জ্যাঙ্গো 2 এবং এসএফটিপি স্টোরেজ এবং এফটিপি স্টোরেজ ব্যবহার করে সমাধান অনুসরণ করার চেষ্টা করেছি এবং আমি নিশ্চিত যে এটি যে কোনও স্টোরেজ ম্যানেজারের সাথে কাজ করবে যা deleteপদ্ধতি প্রয়োগ করেছে । ( deleteপদ্ধতি হ'ল storageবিমূর্ত পদ্ধতিগুলির মধ্যে একটি))

deleteমডেলটির পদ্ধতিটি এমনভাবে ওভাররাইড করুন যাতে উদাহরণটি নিজেকে মুছে ফেলার আগে ফাইল ফাইলগুলি মুছে দেয়:

class Song(models.Model):
    name = models.CharField(blank=True, max_length=100)
    author = models.ForeignKey(User, to_field='id', related_name="id_user2")
    song = models.FileField(upload_to='/songs/')
    image = models.ImageField(upload_to='/pictures/', blank=True)
    date_upload = models.DateField(auto_now_add=True)

    def delete(self, using=None, keep_parents=False):
        self.song.storage.delete(self.song.name)
        self.image.storage.delete(self.song.name)
        super().delete()

এটি আমার পক্ষে বেশ সহজ কাজ করে। আপনি যদি মুছে ফেলার আগে ফাইলটি বিদ্যমান কিনা তা পরীক্ষা করতে চান, আপনি ব্যবহার করতে পারেন storage.exists। যেমন গান উপস্থিত থাকলে self.song.storage.exists(self.song.name)একটি booleanপ্রতিনিধিত্ব করে ফিরিয়ে দেবে । সুতরাং এটি এর মতো দেখাবে:

def delete(self, using=None, keep_parents=False):
    # assuming that you use same storage for all files in this model:
    storage = self.song.storage

    if storage.exists(self.song.name):
        storage.delete(self.song.name)

    if storage.exists(self.image.name):
        storage.delete(self.song.name)

    super().delete()

সম্পাদনা (সংযোজন):

@ হাইম্যান যেমন উল্লেখ করেছেন, এই সমাধান কলিংয়ের মাধ্যমে Song.objects.all().delete()ফাইলগুলি মুছবে না! এটি ঘটছে কারণ ডিফল্ট ম্যানেজারেরSong.objects.all().delete() মোছা ক্যোয়ারী চলছে । সুতরাং আপনি যদি পদ্ধতিগুলি ব্যবহার করে কোনও মডেলের ফাইলগুলি মুছতে সক্ষম হতে চান তবে আপনাকে অবশ্যই একটি কাস্টম ম্যানেজার লিখতে হবে এবং ব্যবহার করতে হবে (কেবল এটির মুছার প্রশ্নটি ওভাররাইড করার জন্য):objects

class CustomManager(models.Manager):
    def delete(self):
        for obj in self.get_queryset():
            obj.delete()

এবং CustomManagerমডেলটি নির্ধারণের জন্য , আপনাকে অবশ্যই objectsআপনার মডেলের অভ্যন্তর প্রারম্ভিক :

class Song(models.Model):
    name = models.CharField(blank=True, max_length=100)
    author = models.ForeignKey(User, to_field='id', related_name="id_user2")
    song = models.FileField(upload_to='/songs/')
    image = models.ImageField(upload_to='/pictures/', blank=True)
    date_upload = models.DateField(auto_now_add=True)
    
    objects = CustomManager() # just add this line of code inside of your model

    def delete(self, using=None, keep_parents=False):
        self.song.storage.delete(self.song.name)
        self.image.storage.delete(self.song.name)
        super().delete()

এখন আপনি যে .delete()কোনও objectsউপ-প্রশ্নের শেষে ব্যবহার করতে পারেন । আমি সহজতম লিখেছি CustomManager, তবে আপনি মুছে ফেলা জিনিস বা আপনি যা চান তার কিছু ফিরিয়ে দিয়ে আপনি এটি আরও ভাল করতে পারেন।


4
হ্যাঁ, আমি মনে করি যে তারা প্রশ্নটি পোস্ট করার পরে তারা সেই বৈশিষ্ট্যটি যুক্ত করেছে।
মার্কোস আগুয়াও 21

4
তবুও মুছুন wenn কলিং বলা হয় না Song.objects.all ()। মোছা ()। অন_ডিলেট = মডেলগুলি দ্বারা যখন ইনস্ট্যান্স মোছা হবে তার জন্য একই। ক্যাসক্যাড।
আরে

@ হায়মন আমি এখনই এটি সমাধান করেছি এবং আমার সমাধানটি এখনই সম্পাদনা করেছি :)
হামিদ্রেজা

4

এখানে এমন একটি অ্যাপ্লিকেশন রয়েছে যা যখনই মডেল মোছা হয় বা কোনও নতুন ফাইল আপলোড করা হয় তখন পুরানো ফাইলগুলি সরিয়ে ফেলবে: জ্যাঞ্জো-স্মার্টফিল্ড

from django.db import models
from smartfields import fields

class Song(models.Model):
    song = fields.FileField(upload_to='/songs/')
    image = fields.ImageField(upload_to='/pictures/', blank=True)

3

পুনঃটুইট করেছেন

আমি ফাইলের পরিবর্তনের সময় কোডে কিছু অনুভব করছি, আপনি যদি একটি নতুন ফাইল তৈরি করেন তবে ত্রুটি উত্পন্ন হয়, কারণ একটি নতুন ফাইল যা কোনও পথ খুঁজে পায়নি। আমি ফাংশনের কোডটি সংশোধন করেছি এবং বাক্যটি বাদ দিয়ে চেষ্টা করেছি / এটি ভালভাবে কাজ করে।

@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """Deletes file from filesystem
    when corresponding `MediaFile` object is changed.
    """
    if not instance.pk:
        return False

    try:
        old_file = MediaFile.objects.get(pk=instance.pk).file
    except MediaFile.DoesNotExist:
        return False

    new_file = instance.file
    if not old_file == new_file:
        try:
            if os.path.isfile(old_file.path):
                os.remove(old_file.path)
        except Exception:
            return False

আমি এটির মুখোমুখি হইনি my আমার কোডটিতে একটি বাগ হতে পারে বা জ্যাঙ্গোতে কিছু পরিবর্তন হয়েছে। আমি আপনার try:ব্লকে নির্দিষ্ট ব্যতিক্রম ধরা পরামর্শ দিচ্ছি , যদিও ( AttributeErrorসম্ভবত?)।
আন্তন স্ট্রগনফ

ওএস লাইব্রেরিটি ব্যবহার করা এতটা ভাল ধারণা নয়, যেহেতু আপনি বিভিন্ন স্টোরেজে স্থানান্তরিত হলে সমস্যাগুলির মুখোমুখি হবেন (উদাহরণস্বরূপ অ্যামাজন এস 3)।
ইগোর পোমারানস্কি

@ ইগোরপোমারানস্কি আপনি অ্যাস.আরমোভ ব্যবহার করার সময় অ্যামাজন এস 3 এর মতো স্টোরেজে কী ঘটবে ??
ড্যানিয়েল গনজালেজ ফার্নান্দেজ

@ ড্যানিয়েলগনজিলেজ ফার্নান্দেজ আমার ধারণা এটি ব্যর্থ হবে (অস্তিত্বহীন পথ সম্পর্কে কিছু ত্রুটির সাথে)। এজন্য জাজানো স্টোরগুলির জন্য বিমূর্ত ব্যবহার করে।
ইগোর পোমারানস্কি

0

এই কোডটি প্রতিবার চলবে যখনই আমি কোনও নতুন চিত্র (লোগো ক্ষেত্র) আপলোড করব এবং লোগো ইতিমধ্যে উপস্থিত রয়েছে কিনা তা পরীক্ষা করে দেখুন, এটি বন্ধ করুন এবং এটি ডিস্ক থেকে সরান। একই পদ্ধতিটি অবশ্যই রিসিভার ফাংশনে তৈরি করা যেতে পারে। আশাকরি এটা সাহায্য করবে.

 #  Returns the file path with a folder named by the company under /media/uploads
    def logo_file_path(instance, filename):
        company_instance = Company.objects.get(pk=instance.pk)
        if company_instance.logo:
            logo = company_instance.logo
            if logo.file:
                if os.path.isfile(logo.path):
                    logo.file.close()
                    os.remove(logo.path)

        return 'uploads/{0}/{1}'.format(instance.name.lower(), filename)


    class Company(models.Model):
        name = models.CharField(_("Company"), null=False, blank=False, unique=True, max_length=100) 
        logo = models.ImageField(upload_to=logo_file_path, default='')
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.