如何使用新图像更新Django模型中的ImageField

时间:2017-04-12 10:09:49

标签: python django django-models

在我的项目中,用户可以上传图像,一旦保存,我可以运行post_save信号来使用Pillow修改图像。在修改图像后,我需要用新图像替换现有图像。现在的问题是,如果我在post_save信号中运行save方法,它将导致最大的递归错误。所以我没有想到使用更新方法但它会引发有关文件中字符的错误。

以下是代码:

   def menuImageLocation(instance,filename):
       return "%s/%s"%(instance,filename)   

   class restaurantMenuImage(models.Model):
     restaurant     = models.ForeignKey(restaurantCreateUpdate)
     title      =   models.CharField(max_length=100,null=True,blank=True)
     menuImage  = models.ImageField(upload_to=menuImageLocation,null=True,blank=True,verbose_name="Menu Image") 

    def __unicode__(self):
        return str(self.restaurant)      

    @receiver(post_save,sender=restaurantMenuImage)
    def modifyMenuImage(sender,instance,**kwargs):

getRestaurant = restaurantCreateUpdate.objects.get(restaurantName=instance.restaurant)
image_path  = instance.menuImage.path
filename    = os.path.basename(image_path)

image_hold  = Image.open(image_path)

image = image_hold.resize((300,300),Image.ANTIALIAS)

temp_loc = "%s/%s/%s/tmp"%(settings.MEDIA_ROOT,"menu",getRestaurant.uniqueID)

if not os.path.exists(temp_loc):
    os.makedirs(temp_loc)

temp_file_path = os.path.join(temp_loc,filename)    
if os.path.exists(temp_file_path):
    temp_path = os.path.join(temp_loc,"%s" %(random.random()))
    os.makedirs(temp_path)
    temp_file_path = os.path.join(temp_path,filename)

temp_image = open(temp_file_path,"w")           

image.save(temp_image,quality=80)

temp_data = open(temp_file_path,"r")

image_file = File(temp_data)
instance.menuImage.save(filename, image_file)

因此,如果我运行代码的最后一行,这将导致最大的递归错误,而不是使用保存方法我试图使用更新方法文件路径,但为此我得到字符超过的错误“image_file”的max_length。非常感谢任何帮助。

先谢谢!

1 个答案:

答案 0 :(得分:0)

在运行最后一行之前,请检查实例的图像路径是否与新图像路径不同。然后代码只运行一次。出现问题,因为当您在模型上调用save时,post_save信号中的代码始终会运行,从而产生无限循环。因此,在post_save信号方法中调用save时需要小心。

这样的事情应该会有所帮助:

USE master;
GO

CREATE PROC DatabaseReIndex(@Database VARCHAR(100)) AS 
BEGIN
  DECLARE @DbID SMALLINT=DB_ID(@Database)--Get Database ID
  IF EXISTS(SELECT * FROM tempdb.sys.objects WHERE name='Indexes') 
  BEGIN --Delete Temp Table if exists, then create
    DROP TABLE TempDb.dbo.Indexes
  END

CREATE TABLE TempDb.dbo.Indexes(IndexTempID INT IDENTITY(1,1),SchemaName NVARCHAR(128),TableName NVARCHAR(128),IndexName NVARCHAR(128),IndexFrag FLOAT)
EXEC ('USE '+@Database+';
INSERT INTO TempDb.dbo.Indexes(TableName,SchemaName,IndexName,IndexFrag)
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,sch.name,ind.name IndexName,indexstats.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats('+@DbID+', NULL, NULL, NULL, NULL) indexstats
INNER JOIN sys.indexes ind ON ind.object_id = indexstats.object_id AND ind.index_id = indexstats.index_id
INNER JOIN sys.objects obj on obj.object_id=indexstats.object_id
INNER JOIN sys.schemas as sch ON sch.schema_id = obj.schema_id
WHERE indexstats.avg_fragmentation_in_percent > 10 AND indexstats.index_type_desc<>''HEAP''
ORDER BY indexstats.avg_fragmentation_in_percent DESC')--Get index data and fragmentation, set the percentage as high or low as you need

DECLARE @IndexTempID BIGINT=0,@SchemaName NVARCHAR(128),@TableName NVARCHAR(128),@IndexName NVARCHAR(128),@IndexFrag FLOAT
SELECT * FROM TempDb.dbo.Indexes --View your results, comment out if not needed...

-- Loop through the indexes
WHILE @IndexTempID IS NOT NULL 
  BEGIN
    SELECT @SchemaName=SchemaName,@TableName=TableName,@IndexName=IndexName,@IndexFrag=IndexFrag FROM TempDb.dbo.Indexes WHERE IndexTempID=@IndexTempID
    IF @IndexName IS NOT NULL AND @SchemaName IS NOT NULL AND @TableName IS NOT NULL 
    BEGIN
      IF @IndexFrag<30. 
      BEGIN --Low fragmentation can use re-organise, set at 30 as per most articles
        PRINT 'USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE'
        EXEC('USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REORGANIZE')
      END
    ELSE 
      BEGIN --High fragmentation needs re-build
        PRINT 'USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REBUILD'
        EXEC('USE '+@Database+'; ALTER INDEX ' + @IndexName + N' ON ' + @SchemaName + N'.' + @TableName + N' REBUILD')
      END
    END

    SET @IndexTempID=(SELECT MIN(IndexTempID) FROM TempDb.dbo.Indexes WHERE IndexTempID>@IndexTempID)
  END
END

DROP TABLE TempDb.dbo.Indexes

GO