簡體   English   中英

Django FileField存儲選項

[英]Django FileField storage option

我有這個型號:

class UserProfile(models.Model):
    #..........
    photo = models.ImageField(upload_to = get_upload_file_name,
                              storage = OverwriteStorage(),
                              blank = True, null = True,
                              height_field = 'photo_height',
                              width_field = 'photo_width')

這是我的存儲功能:

class OverwriteStorage(FileSystemStorage):
    def _save(self, name, content):
        self.delete(r'.*')
        return super(OverwriteStorage, self)._save(name, content)

    def get_available_name(self, name):
        return name

我該怎么做以下兩件事:

  1. 每當用戶上傳文件(即圖像)時,我想刪除舊文件,無論名稱是否相同。 我試圖刪除任何與上述正則表達式匹配的內容,但這不起作用。

  2. 如果用戶上傳名為“me.jpg”的圖像,我想以不同的方式重命名,具體取決於用戶的用戶名。 所以我會做一些像return super(OverwriteStorage, self)._save(SOMETHING_ELSE_HERE, content)如何做到這一點? 我可以將其他參數傳遞給OverwriteStorage函數嗎?

還有第三個問題:我為這個表單創建了一個ModelForm。 因此用戶可以上傳圖像。 因此,當有人按下“選擇文件”時,會彈出一個窗口窗口以瀏覽和選擇照片。 我怎么才能在這里顯示某些文件? (例如,只有.jpg和.jpeg文件)

謝謝!

編輯: get_upload_file_name函數

def get_upload_file_name(instance, filename):
    return "%s/%s/profile_photo/%s" % (instance.user.username[0].lower(), instance.user.username, filename)

編輯2:我已經包含了我的models.py

import datetime
import os
import urllib2, urlparse
import re

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
from django.core.files.storage import FileSystemStorage
from django.contrib.staticfiles import finders
from django.conf import settings
from django.core.files.base import ContentFile
from django.forms import widgets

now = datetime.datetime.now()

def get_upload_file_name(instance, filename):
    now = datetime.datetime.now()

    file_name = str(now.year)  + '_' + \
                str(now.month) + '_' + \
                str(now.day)   + '_' + \
                str(now.hour)  + '_' + \
                str(now.minute)+ '_' + \
                str(now.second)+ '.' + \
                filename.split('.')[-1]

    return "%s/%s/profile_photo/%s" % (instance.user.username[0].lower(),
                                       instance.user.username,
                                       file_name)

class OverwriteStorage(FileSystemStorage):
    def _save(self, name, content):
        self.delete(name)
        return super(OverwriteStorage, self)._save(name, content)

class UserProfileManager(models.Manager):

    def create_user_profile(self, user):
        user_profile = self.create(user = user)
        return user_profile

class UserProfile(models.Model):

    ### it is now.year - 13 because legitimate persons on this website should be over 14 years old
    YEARS = tuple(
                  zip([format(x,'04d') for x in range(now.year-120, now.year-13)],
                      [format(x,'04d') for x in range(now.year-120, now.year-13)]
                      )
                  )
    MONTHS = (
              ('January','January'),('February','February'),('March','March'),('April','April'),
              ('May','May'), ('June','June'),('July','July'),('August','August'),
              ('September','September'),('October','October'),('November','November'), ('December', 'December')

             )
    GENDERS = (('M', 'Male'), ('F', 'Female'))

    user = models.OneToOneField(User, related_name = 'MoreAboutUser', unique=True, verbose_name=_('user'))
    year_of_birth = models.CharField(max_length=10, blank = True,  null = True, choices=YEARS)
    month_of_birth = models.CharField(max_length=10, blank = True,  null = True, choices=MONTHS)
    gender = models.CharField(max_length=1, blank = True,  null = True, choices=GENDERS)
    photo = models.ImageField(upload_to = get_upload_file_name,
                              blank = True, null = True,
                              height_field = 'photo_height',
                              width_field = 'photo_width',
                              #widget = widgets.FileInput(attrs={'accept': 'image/gif,image/png,image/jpeg'})
                              )
    photo_height = models.PositiveIntegerField(blank = True, default = 0)
    photo_width = models.PositiveIntegerField(blank = True, default = 0)
    creation_time = models.DateTimeField(auto_now_add = True, auto_now = False)
    update_time = models.DateTimeField(auto_now_add = False, auto_now = True)

    class Meta:
            verbose_name = _('user profile')
            verbose_name_plural = _('user profiles')

    def __unicode__(self):
        return self.user.username

    objects = UserProfileManager()

    def get_profile_photo_url(self):
        if self.photo and hasattr(self.photo, 'url'):
            return self.photo.url
        else:
            return '/static/images/generic_profile_photo.jpg'

def create_user_profile(sender, instance, created, **kwargs):

    if created:
        try:
            profile = UserProfile.objects.create_user_profile(user = instance)
            profile.save()
        except:
            pass

post_save.connect(create_user_profile, sender=User)

存儲API對您的模型一無所知,因此不能考慮其他字段的值 - 它不知道存儲在該字段中的舊文件的名稱,也不知道哪個用戶擁有模型記錄。

你似乎在正確的軌道上提供upload_to = get_upload_file_name選項,你ImageField ; get_upload_file_name函數(您未在問題中發布)將能夠為圖像構建基於用戶的文件名,因為它獲取對模型實例的引用,因此它知道擁有模型實例的用戶。

至於刪除舊文件,您可能需要在模型的save()方法中實現它。 在這一點上找到現有模型實例中的舊文件名為時已晚,因為它的photo字段已經使用其新值更新; 您仍然可以從數據庫中檢索現有記錄的副本,並通過它刪除舊文件。 這是一個示例實現:

class UserProfile(models.Model):

    ...

    def save(self, *args, **kwargs):

        # grab a copy of the old record from the database
        oldrec = type(self).objects.get(pk=self.pk)

        # save the current instance, and keep the result
        result = super(UserProfile, self).save(*args, **kwargs)

        # if the path is the same, the file is overwritten already
        # and no deletion is necessary
        if oldrec.photo.path != self.photo.path:
            oldrec.photo.delete()

        # return the result received from the parent save() method
        return result

要為文件選擇指定可接受的類型,您需要為將為您的字段呈現的<input>標記提供accept屬性; 您需要在自定義表單中覆蓋窗口小部件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM