Django Anular guardar para modelo


134

Antes de guardar el modelo, cambio el tamaño de una imagen. Pero, ¿cómo puedo verificar si se agregó una nueva imagen o solo una descripción actualizada, para poder omitir la reescalada cada vez que se guarda el modelo?

class Model(model.Model):
    image=models.ImageField(upload_to='folder')
    thumb=models.ImageField(upload_to='folder')
    description=models.CharField()


    def save(self, *args, **kwargs):
        if self.image:
            small=rescale_image(self.image,width=100,height=100)
            self.image_small=SimpleUploadedFile(name,small_pic)
        super(Model, self).save(*args, **kwargs)

Quiero volver a escalar solo si se carga una nueva imagen o si se actualiza la imagen, pero no cuando se actualiza la descripción.


¿Está cambiando el tamaño a un tamaño fijo de 100x100?
bdd

3
U puede encontrar útil django-imagekit
vikingosegundo

Respuestas:


135

Algunos pensamientos:

class Model(model.Model):
    _image=models.ImageField(upload_to='folder')
    thumb=models.ImageField(upload_to='folder')
    description=models.CharField()

    def set_image(self, val):
        self._image = val
        self._image_changed = True

        # Or put whole logic in here
        small = rescale_image(self.image,width=100,height=100)
        self.image_small=SimpleUploadedFile(name,small_pic)

    def get_image(self):
        return self._image

    image = property(get_image, set_image)

    # this is not needed if small_image is created at set_image
    def save(self, *args, **kwargs):
        if getattr(self, '_image_changed', True):
            small=rescale_image(self.image,width=100,height=100)
            self.image_small=SimpleUploadedFile(name,small_pic)
        super(Model, self).save(*args, **kwargs)

No estoy seguro de si funcionaría bien con todas las herramientas pseudo-auto django (Ejemplo: ModelForm, contrib.admin, etc.).


1
Se ve bien. Pero no puedo cambiar el nombre de la imagen a _image. ¿Eso es importante?
Pol

Ok, lo resolví con db_column = 'image'. ¡Pero el acero no funciona!
Pol

1
Es un método muy interesante ... por no lo entiendo completamente. ¿Puedes explicarlo de manera más explicativa? ¿O sembrar algún artículo?
Pol

A mí tampoco me funcionó. set_image nunca llamado. Parece que algunas cosas de Django no son oficialmente compatibles
Ivan Borshchov

16

Verifique el campo pk del modelo. Si es Ninguno, entonces es un objeto nuevo.

class Model(model.Model):
    image=models.ImageField(upload_to='folder')
    thumb=models.ImageField(upload_to='folder')
    description=models.CharField()


    def save(self, *args, **kwargs):
        if 'form' in kwargs:
            form=kwargs['form']
        else:
            form=None

        if self.pk is None and form is not None and 'image' in form.changed_data:
            small=rescale_image(self.image,width=100,height=100)
            self.image_small=SimpleUploadedFile(name,small_pic)
        super(Model, self).save(*args, **kwargs)

Editar: agregué una marca para 'imagen' en form.changed_data. Esto supone que está utilizando el sitio de administración para actualizar sus imágenes. También tendrá que anular el método predeterminado save_model como se indica a continuación.

class ModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save(form=form)

Creo que tiene razón ... suponiendo que esté usando el sitio de administración, puede anular save_model en su AdminModel para pasar el formulario y guardarlo, y verificar si 'image' está en form.changed_data. Actualizaré tan pronto como tenga tiempo.
DM Graves

Esto solo funciona si el objeto es nuevo como usted dice. Si carga una nueva imagen, el cambio de escala no se activará.
Jonathan

2
"self.pk is None" no funciona si uno especifica el id, por lo tanto: Model.objects.get_or_create (id = 234, ...) no funcionará en esta solución
loco

6

Puede proporcionar un argumento adicional para confirmar que se publica una nueva imagen.
Algo como:

def save(self, new_image=False, *args, **kwargs):
    if new_image:
        small=rescale_image(self.image,width=100,height=100)
        self.image_small=SimpleUploadedFile(name,small_pic)
    super(Model, self).save(*args, **kwargs)

o pasar solicitud variable

def save(self, request=False, *args, **kwargs):
    if request and request.FILES.get('image',False):
        small=rescale_image(self.image,width=100,height=100)
        self.image_small=SimpleUploadedFile(name,small_pic)
    super(Model, self).save(*args, **kwargs)

Creo que esto no romperá su salvación cuando se llama simplemente.

Puede poner esto en su admin.py para que también funcione con el sitio de administración (para la segunda de las soluciones anteriores):

class ModelAdmin(admin.ModelAdmin):

    ....
    def save_model(self, request, obj, form, change): 
        instance = form.save(commit=False)
        instance.save(request=request)
        return instance

me dice que: el objeto 'WSGIRequest' no tiene atributo 'ARCHIVO'
Pol

sry sus ARCHIVOS en lugar de ARCHIVO, actualizado a request.FILES.get ('image', False) en lugar de request.FILES ['image'], esto evitará la excepción
crodjer

3

Lo que hice para lograr el objetivo fue hacer esto ...

# I added an extra_command argument that defaults to blank
def save(self, extra_command="", *args, **kwargs):

y debajo del método save () es esto ...

# override the save method to create an image thumbnail
if self.image and extra_command != "skip creating photo thumbnail":
    # your logic here

así que cuando edito algunos campos pero no edito la imagen, pongo esto ...

Model.save("skip creating photo thumbnail")

puede reemplazar el texto "skip creating photo thumbnail"con "im just editing the description"o un texto más formal.

Espero que este ayude!


2

Consulte en la base de datos un registro existente con la misma PK. Compare los tamaños de archivo y las sumas de verificación de las imágenes nuevas y existentes para ver si son iguales.


1

Django 3: anulación de métodos de modelo predefinidos

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs)  # Call the "real" save() method.
        do_something_else()

Es importante recordar llamar al método de superclase, ese es el super().save(*args, **kwargs)negocio, para asegurarse de que el objeto aún se guarde en la base de datos. Si olvida llamar al método de superclase, el comportamiento predeterminado no ocurrirá y la base de datos no será tocada.


0

En la nueva versión es así:

def validate(self, attrs):
    has_unknown_fields = set(self.initial_data) - set(self.fields.keys())
    if has_unknown_fields:
        raise serializers.ValidationError("Do not send extra fields")
    return attrs

0

He encontrado otra forma simple de almacenar los datos en la base de datos

modelos.py

class LinkModel(models.Model):
    link = models.CharField(max_length=500)
    shortLink = models.CharField(max_length=30,unique=True)

En la base de datos solo tengo 2 variables

views.py

class HomeView(TemplateView):
    def post(self,request, *args, **kwargs):
        form = LinkForm(request.POST)

        if form.is_valid():
            text = form.cleaned_data['link'] # text for link

        dbobj = LinkModel()
        dbobj.link = text
        self.no = self.gen.generateShortLink() # no for shortLink
        dbobj.shortLink = str(self.no)
        dbobj.save()         # Saving from views.py

En esto, he creado la instancia de model solo en views.py y colocando / guardando datos en 2 variables solo de vistas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.