Django मॉडल ImageField फ़ाइल अपलोड करते समय प्रत्येक बार एक नेस्टेड फ़ोल्डर बनाता है
मुझे यकीन है कि मैं मूर्खतापूर्ण कुछ याद कर रहा हूं, लेकिन मैं भ्रमित हूं।
मेरी प्रोफ़ाइल के लिए मेरे पास निम्न मॉडल है:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(
default="default.jpg",
upload_to="profile_pics/",
validators=[FileExtensionValidator(["jpeg", "jpg", "png"])],
)
def __str__(self):
return f"{self.user.username} Profile"
def save(self, *args, **kwargs):
if self.image:
self.image = make_thumbnail(self.image, size=(200, 200))
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
लेकिन profile_pics
फ़ोल्डर घोंसला बनाए रखता है, इसलिए मेरी फ़ोल्डर संरचना इस तरह दिखना शुरू होती है:

सेटिंग्स में मेरे चर सामान्य दिखेंगे, मेरा मानना है:
BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
मेरा मानना है कि नेस्टिंग फोल्डर के साथ समस्या मेरी प्रोफाइल क्लास में विशेष रूप से इसे बचाने के तरीके के साथ उत्पन्न होती है:
def save(self, *args, **kwargs):
if self.image:
self.image = make_thumbnail(self.image, size=(200, 200))
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
जो मेरे संकेतों से प्रेरित है:
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
यह फ़ोल्डर्स को क्यों नेस्ट कर रहा है?
मैं ब्लॉग पोस्ट छवियों पर समान सहेजें विधि का उपयोग कर रहा हूं और वहां फ़ोल्डर्स घोंसला नहीं बनाते हैं।
मैं क्या खो रहा हूँ?
पुनश्च: यदि यह मदद करता है, तो यह make_thumbnail है:
from io import BytesIO
from django.core.files import File
from PIL import Image
def make_thumbnail(image, size=(600, 600)):
im = Image.open(image)
if im.format == "JPEG":
im.convert("RGB")
im.thumbnail(size)
thumb_io = BytesIO()
im.save(thumb_io, "JPEG", quality=85)
image = File(thumb_io, name=image.name)
else:
im.convert("RGBA")
im.thumbnail(size)
thumb_io = BytesIO()
im.save(thumb_io, "PNG", quality=85)
image = File(thumb_io, name=image.name)
return image
संपादित करें:
मैं गलती से इस समाधान पर पहुंच गया, जो मुख्य मुद्दे से बच रहा है, हालांकि मुझे यकीन नहीं है कि यह कितना कुशल हो सकता है:
def save(self, *args, **kwargs):
if self.image:
self.image = make_thumbnail(self.image, size=(200, 200))
image_name = self.image.name
ext = image_name.split(".")[-1]
filename = "%s.%s" % (uuid.uuid4(), ext)
clean_name = os.path.join("", filename)
self.image.name = clean_name
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
जवाब
मुझे यकीन है कि आप इस पोस्ट को अपनी आवश्यकताओं को समायोजित करना चाहते थे । लेखक के पास कोई समस्या नहीं है, क्योंकि वह "पुन: उपयोग नहीं कर रहा है जो वह बचत कर रहा है"।
self.image
विशेषता है name
। जब आप जांचते हैं कि क्या यह मौजूद है ( if self.image
), तो इसका नाम पहले से ही है। फिर प्रत्येक अद्यतन के साथ आप पहले से ही आकार बदलने वाली छवि का आकार परिवर्तन करते रहते हैं, जो upload_to
पथ में पहले से मौजूद छवि नाम को जोड़ता रहता है, इसलिए प्रत्येक पुनरावृत्ति के साथ यह करता है upload_to
+ self.image.name
। लेकिन self.image.name
पहले से ही है /profile_pics/...
।
इस समस्या को हल करने के लिए, बस is_resized
कॉलम जोड़ें ।
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(
default="default.jpg",
upload_to="profile_pics/",
validators=[FileExtensionValidator(["jpeg", "jpg", "png"])],
)
is_resized = models.BooleanField(default=False)
def __str__(self):
return f"{self.user.username} Profile"
def save(self, *args, **kwargs):
if self.image and not self.is_resized:
self.is_resized = True
self.image = make_thumbnail(self.image, size=(200, 200))
super().save(*args, **kwargs)
जब भी छवि में बदलाव हो, बस सेट is_resized
करना याद रखें False
।
साइड नोट, सामान्य रूप से संकेत एक बुरा अभ्यास है। मैं यह भी नहीं सोचता कि दो संकेतों का एक अच्छा विचार है जो समान वस्तुओं पर काम करते हैं।
यदि आपको वास्तव में उनके पास होने की आवश्यकता है, तो उन्हें एकल संकेत के साथ बदलने पर विचार करें।
@receiver(post_save, sender=User)
def handle_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
instance.profile.save()
हालाँकि यह बेहतर होगा यदि आप अपने विचार में थंबनेल का आकार बदल रहे हैं।
Django में एक चीज़ है जिसे 'डुप्लिकेट सिग्नल' कहा जाता है। यह हर जगह होता है आपकी परियोजना मॉड्यूल को आयात करती है जहां आप संकेतों को परिभाषित करते हैं, क्योंकि सिग्नल पंजीकरण आयात किए जाने के दौरान कई बार चलता है।
हो सकता है कि आप अपने रिसीवर फ़ंक्शन को पहचानने के लिए dispatch_uid तर्क के रूप में एक विशिष्ट पहचानकर्ता को पास करके अपनी समस्या को हल कर सकें।
from django.core.signals import request_finished
request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")
स्रोत: https://docs.djangoproject.com/en/3.1/topics/signals/