Django. Ignora il salvataggio per il modello


134

Prima di salvare il modello, ridimensiono un'immagine. Ma come posso verificare se una nuova immagine è stata aggiunta o solo una descrizione aggiornata, così posso saltare il ridimensionamento ogni volta che il modello viene salvato?

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)

Voglio ridimensionare solo se la nuova immagine è stata caricata o l'immagine è stata aggiornata, ma non quando la descrizione è stata aggiornata.


Stai ridimensionando a una dimensione fissa di 100x100?
bdd,

Risposte:


135

Alcuni pensieri:

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)

Non sono sicuro che funzionerebbe bene con tutti gli strumenti pseudo-auto django (Esempio: ModelForm, contrib.admin ecc.).


1
Sembra bello. Ma non posso rinominare l'immagine in _image. È importante?
Pol

Ok l'ho risolto con db_column = 'image'. Ma l'acciaio non funziona!
Pol

1
È un metodo molto interessante .. da non capirlo completamente. Puoi per favore spiegarlo in modo più esplicito? O seminare qualche articolo?
Pol

Non ha funzionato anche per me. set_image non ha mai chiamato. Sembra che alcune cose di Django non ufficialmente supportate
Ivan Borshchov,

16

Controlla il campo pk del modello. Se è None, allora è un nuovo oggetto.

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)

Modifica: ho aggiunto un segno di spunta per "immagine" in form.changed_data. Ciò presuppone che tu stia utilizzando il sito di amministrazione per aggiornare le tue immagini. Dovrai anche sostituire il metodo save_model predefinito come indicato di seguito.

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

Penso che tu abbia ragione ... supponendo che stia usando il sito di amministrazione, può sovrascrivere il save_model nel suo AdminModel per passare il modulo per salvare e controllare se 'image' è in form.changed_data. Aggiornerò non appena avrò tempo.
DM Graves,

Funziona solo se l'oggetto è nuovo come dici tu. Se carichi una nuova foto, il ridimensionamento non si attiverà.
Jonathan,

2
"self.pk è Nessuno" non funziona se si specifica l'id, quindi: Model.objects.get_or_create (id = 234, ...) non funzionerà in questa soluzione
dadi

6

È possibile fornire ulteriori argomenti per confermare che viene pubblicata una nuova immagine.
Qualcosa di simile a:

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 passa la variabile di richiesta

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)

Penso che questi non spezzeranno il tuo salvataggio se chiamato semplicemente.

Puoi metterlo nel tuo admin.py in modo che funzioni anche con il sito di amministrazione (per la seconda delle soluzioni precedenti):

class ModelAdmin(admin.ModelAdmin):

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

mi dice che: l'oggetto 'WSGIRequest' non ha attributo 'FILE'
Pol

sry i suoi FILES anziché FILE, aggiornati a request.FILES.get ('image', False) invece di request.FILES ['image'], questo eviterà l'eccezione
crodjer

3

Quello che ho fatto per raggiungere l'obiettivo è stato fare questo ...

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

e sotto il metodo save () è questo ..

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

quindi quando modifico alcuni campi ma non modifico l'immagine, lo metto ..

Model.save("skip creating photo thumbnail")

puoi sostituire il testo "skip creating photo thumbnail"con "im just editing the description"o con un testo più formale.

Spero che questo aiuti!


2

Eseguire una query sul database per un record esistente con lo stesso PK. Confronta le dimensioni dei file e i checksum delle immagini nuove ed esistenti per vedere se sono uguali.


1

Django 3: Sostituzione dei metodi del modello predefinito

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()

È importante ricordare di chiamare il metodo superclasse - che è super().save(*args, **kwargs)quell'azienda - per assicurarsi che l'oggetto venga ancora salvato nel database. Se si dimentica di chiamare il metodo superclasse, il comportamento predefinito non si verificherà e il database non verrà toccato.


0

Nella nuova versione è così:

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

Mi sono trovato un altro modo semplice per archiviare i dati nel database

models.py

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

Nel database ho solo 2 variabili

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

In questo ho creato l'istanza del modello solo in views.py e inserendo / salvando i dati in 2 variabili solo dalle viste.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.