Django. Speichern für Modell überschreiben

133

Vor dem Speichern des Modells habe ich die Größe eines Bildes geändert. Aber wie kann ich überprüfen, ob ein neues Bild hinzugefügt oder nur die Beschreibung aktualisiert wurde, damit ich die Neuskalierung jedes Mal überspringen kann, wenn das Modell gespeichert wird?

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)

Ich möchte nur neu skalieren, wenn ein neues Bild geladen oder aktualisiert wurde, aber nicht, wenn die Beschreibung aktualisiert wurde.

Pol
quelle
Ändern Sie die Größe auf eine feste Größe von 100 x 100?
Bdd
3
U kann django-imagekit nützlich finden
vikingosegundo

Antworten:

133

Einige Gedanken:

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)

Ich bin mir nicht sicher, ob es mit allen Pseudo-Auto-Django-Tools gut funktionieren würde (Beispiel: ModelForm, Contrib.admin usw.).

petraszd
quelle
1
Sieht gut aus. Aber ich kann das Bild nicht in _image umbenennen. Ist das wichtig?
Pol
Ok, ich habe es mit db_column = 'image' gelöst. Aber es funktioniert nicht!
Pol
1
Es ist eine sehr interessante Methode. Ich verstehe sie nicht ganz. Können Sie es bitte näher erläutern? Oder einen Artikel säen?
Pol
Es funktioniert auch nicht bei mir. set_image wurde nie aufgerufen. Sieht so aus, als hätten einige Django-Sachen nicht offiziell unterstützt
Ivan Borshchov
16

Überprüfen Sie das pk-Feld des Modells. Wenn es None ist, ist es ein neues Objekt.

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)

Bearbeiten: Ich habe in form.changed_data einen Check für 'image' hinzugefügt. Dies setzt voraus, dass Sie die Admin-Site verwenden, um Ihre Bilder zu aktualisieren. Sie müssen auch die unten angegebene Standardmethode save_model überschreiben.

class ModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save(form=form)
DM Graves
quelle
Ich denke, Sie haben Recht ... vorausgesetzt, er verwendet die Admin-Site, kann er das save_model in seinem AdminModel überschreiben, um das Formular zum Speichern weiterzuleiten, und prüfen, ob 'image' in form.changed_data enthalten ist. Ich werde aktualisieren, sobald ich Zeit habe.
DM Graves
Dies funktioniert nur, wenn das Objekt wie gesagt neu ist. Wenn Sie ein neues Bild hochladen, wird die Neuskalierung nicht ausgelöst.
Jonathan
2
"self.pk is None" funktioniert nicht, wenn man die ID angibt, also: Model.objects.get_or_create (id = 234, ...) funktioniert in dieser Lösung nicht
Nuts
6

Sie können ein zusätzliches Argument angeben, um zu bestätigen, dass ein neues Bild veröffentlicht wurde.
Etwas wie:

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)

oder Anforderungsvariable übergeben

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)

Ich denke, diese werden Ihre Rettung nicht brechen, wenn Sie einfach angerufen werden.

Sie können dies in Ihre admin.py einfügen, damit dies auch mit der Admin-Site funktioniert (für die zweite der oben genannten Lösungen):

class ModelAdmin(admin.ModelAdmin):

    ....
    def save_model(self, request, obj, form, change): 
        instance = form.save(commit=False)
        instance.save(request=request)
        return instance
Crodjer
quelle
es sagt mir, dass: 'WSGIRequest' Objekt kein Attribut 'FILE' hat
Pol
sry seine DATEIEN anstelle von DATEI, aktualisiert auf request.FILES.get ('image', False) anstelle von request.FILES ['image'], dies wird die Ausnahme vermeiden
crodjer
3

Was ich getan habe, um das Ziel zu erreichen, war dies zu erreichen.

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

und unter der save () -Methode ist dies ..

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

Wenn ich also einige Felder bearbeite, aber das Bild nicht bearbeite, setze ich dies ein.

Model.save("skip creating photo thumbnail")

Sie können das ersetzen "skip creating photo thumbnail"mit"im just editing the description" oder einem formellere Text.

Hoffe das hilft!

bonbon.langes
quelle
2

Fragen Sie die Datenbank nach einem vorhandenen Datensatz mit derselben PK ab. Vergleichen Sie die Dateigrößen und Prüfsummen der neuen und vorhandenen Bilder, um festzustellen, ob sie identisch sind.

Ignacio Vazquez-Abrams
quelle
1

Django 3: Überschreiben vordefinierter Modellmethoden

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

Denken Sie daran, die Superclass-Methode aufzurufen - das ist das super().save(*args, **kwargs)Geschäft -, um sicherzustellen, dass das Objekt weiterhin in der Datenbank gespeichert wird. Wenn Sie vergessen, die Superclass-Methode aufzurufen, tritt das Standardverhalten nicht auf und die Datenbank wird nicht berührt.

Panchicore
quelle
0

In der neuen Version ist es so:

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
Dan Goriaynov
quelle
0

Ich habe einen anderen einfachen Weg gefunden, um die Daten in der Datenbank zu speichern

models.py

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

In der Datenbank habe ich nur 2 Variablen

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 diesem Fall habe ich die Instanz des Modells nur in views.py erstellt und Daten nur aus Ansichten in 2 Variablen eingefügt / gespeichert.

Devendra Bhat
quelle