django - copiar archivo de un modelo a otro
copy filefield (5)
Tengo 2 modelos simples:
class UploadImage(models.Model):
Image = models.ImageField(upload_to="temp/")
class RealImage(models.Model):
Image = models.ImageField(upload_to="real/")
Y una forma
class RealImageForm(ModelForm):
class Meta:
model = RealImage
Necesito guardar el archivo de UploadImage en RealImage. Cómo podría hacer esto. El siguiente código no funciona
realform.Image=UploadImage.objects.get(id=image_id).Image
realform.save()
Tnx por ayuda.
Intenta hacer eso sin usar un formulario. Sin saber el error exacto que está obteniendo, solo puedo especular que el método clean () del formulario genera un error debido a una falta de coincidencia en el parámetro upload_to.
Lo que me lleva al próximo punto, si está tratando de copiar la imagen de ''temp /'' a ''real /'', tendrá que hacer un manejo de archivos para mover el archivo usted mismo (más fácil si tiene PIL):
import Image
from django.conf import settings
u = UploadImage.objects.get(id=image_id)
im = Image.open(settings.MEDIA_ROOT + str(u.Image))
newpath = ''real/'' + str(u.Image).split(''/'', 1)[1]
im.save(settings.MEDIA_ROOT + newpath)
r = RealImage.objects.create(Image=newpath)
Espero que haya ayudado ...
Tuve el mismo problema y lo resolví así, espero que ayude a cualquiera:
# models.py
class A(models.Model):
# other fields...
attachment = FileField(upload_to=''a'')
class B(models.Model):
# other fields...
attachment = FileField(upload_to=''b'')
# views.py or any file you need the code in
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django.core.files.base import ContentFile
from main.models import A, B
obj1 = A.objects.get(pk=1)
# You and either copy the file to an existent object
obj2 = B.objects.get(pk=2)
# or create a new instance
obj2 = B(**some_params)
tmp_file = StringIO(obj1.attachment.read())
tmp_file = ContentFile(tmp_file.getvalue())
url = obj1.attachment.url.split(''.'')
ext = url.pop(-1)
name = url.pop(-1).split(''/'')[-1] # I have my files in a remote Storage, you can omit the split if it doesn''t help you
tmp_file.name = ''.''.join([name, ext])
obj2.attachment = tmp_file
# Remember to save you instance
obj2.save()
Inspirado por la solución de Gerard, se me ocurrió el siguiente código:
from django.core.files.base import ContentFile
#...
class Example(models.Model):
file = models.FileField()
def duplicate(self):
"""
Duplicating this object including copying the file
"""
new_example = Example()
new_file = ContentFile(self.file.read())
new_file.name = self.file.name
new_example.file = new_file
new_example.save()
Esto realmente irá tan lejos como renombrar el archivo agregando un "_1" al nombre del archivo para que tanto el archivo original como esta nueva copia del archivo puedan existir en el disco al mismo tiempo.
Actualice la solución de Gerard para manejarlo de una manera genérica:
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django.core.files.base import ContentFile
init_str = "src_obj." + src_field_name + ".read()"
file_name_str = "src_obj." + src_field_name + ".name"
try:
tmp_file = StringIO(eval(str(init_str)))
tmp_file = ContentFile(tmp_file.getvalue())
tmp_file.name = os.path.basename(eval(file_name_str))
except AttributeError:
tmp_file = None
if tmp_file:
try:
dest_obj.__dict__[dest_field_name] = tmp_file
dest_obj.save()
except KeyError:
pass
Variable utilizada:
- src_obj = objeto de enlace de origen.
- src_field_name = Nombre del campo de archivos del objeto de archivo adjunto fuente.
- dest_obj = objeto de destino de destino.
- dest_field_name = Nombre de FileField del objeto de destino de destino.
Aunque esto es tarde, pero abordaría este problema así,
class UploadImage(models.Model):
Image = models.ImageField(upload_to="temp/")
# i need to delete the temp uploaded file from the file system when i delete this model
# from the database
def delete(self, using=None):
name = self.Image.name
# i ensure that the database record is deleted first before deleting the uploaded
# file from the filesystem.
super(UploadImage, self).delete(using)
self.Image.storage.delete(name)
class RealImage(models.Model):
Image = models.ImageField(upload_to="real/")
# in my view or where ever I want to do the copying i''ll do this
import os
from django.core.files import File
uploaded_image = UploadImage.objects.get(id=image_id).Image
real_image = RealImage()
real_image.Image = File(uploaded_image, uploaded_image.name)
real_image.save()
uploaded_image.close()
uploaded_image.delete()
Si estuviera usando un formulario modelo para manejar el proceso, lo haré
# django model forms provides a reference to the associated model via the instance property
form.instance.Image = File(uploaded_image, os.path.basename(uploaded_image.path))
form.save()
uploaded_image.close()
uploaded_image.delete()
Tenga en cuenta que me aseguro de que el archivo uploaded_image esté cerrado porque llamar a real_image.save () abrirá el archivo y leerá su contenido. Eso es manejado por el sistema de almacenamiento utilizado por la instancia de ImageField