Django. Remplacer l'enregistrement pour le modèle

134

Avant d'enregistrer le modèle, je redimensionne une image. Mais comment puis-je vérifier si une nouvelle image a été ajoutée ou simplement une description mise à jour, afin de pouvoir ignorer le redimensionnement à chaque fois que le modèle est enregistré?

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)

Je souhaite redimensionner uniquement si une nouvelle image est chargée ou une image mise à jour, mais pas lorsque la description est mise à jour.

Pol
la source
Redimensionnez-vous à une taille fixe de 100 x 100?
bdd du
3
Vous pouvez trouver django-imagekit utile
vikingosegundo

Réponses:

135

Quelques idées:

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)

Je ne sais pas si cela fonctionnerait bien avec tous les outils pseudo-automatiques de django (Exemple: ModelForm, contrib.admin etc).

Petraszd
la source
1
À l'air cool. Mais je ne peux pas renommer l'image en _image. Est-ce important?
Pol
Ok, je l'ai résolu avec db_column = 'image'. Mais l'acier ne fonctionne pas!
Pol
1
C'est une méthode très intéressante .. par je ne la comprends pas entièrement. Pouvez-vous s'il vous plaît l'expliquer plus explicitement? Ou semer un article?
Pol
Cela n'a pas fonctionné pour moi aussi. set_image n'a jamais été appelé. On dirait que certains Django ne sont pas officiellement pris en charge
Ivan Borshchov
16

Vérifiez le champ pk du modèle. Si c'est None, alors c'est un nouvel objet.

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)

Edit: J'ai ajouté un chèque pour 'image' dans form.changed_data. Cela suppose que vous utilisez le site d'administration pour mettre à jour vos images. Vous devrez également remplacer la méthode save_model par défaut comme indiqué ci-dessous.

class ModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save(form=form)
DM Graves
la source
Je pense que vous avez raison ... en supposant qu'il utilise le site d'administration, il peut remplacer le save_model dans son AdminModel pour passer le formulaire à enregistrer, et vérifier si 'image' est au format form.changed_data. Je mettrai à jour dès que j'aurai le temps.
DM Graves
Cela ne fonctionne que si l'objet est nouveau comme vous le dites. Si vous téléchargez une nouvelle image, la remise à l'échelle ne se déclenchera pas.
Jonathan
2
"self.pk is None" ne fonctionne pas si on spécifie l'id, donc: Model.objects.get_or_create (id = 234, ...) ne fonctionnera pas dans cette solution
écrous
6

Vous pouvez fournir un argument supplémentaire pour confirmer qu'une nouvelle image est publiée.
Quelque chose comme:

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)

ou passer la variable de demande

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)

Je pense que ceux-ci ne casseront pas votre sauvegarde lorsqu'ils sont appelés simplement.

Vous pouvez le mettre dans votre admin.py afin que cela fonctionne également avec le site d'administration (pour la deuxième des solutions ci-dessus):

class ModelAdmin(admin.ModelAdmin):

    ....
    def save_model(self, request, obj, form, change): 
        instance = form.save(commit=False)
        instance.save(request=request)
        return instance
crodjer
la source
il me dit que: l'objet 'WSGIRequest' n'a pas d'attribut 'FILE'
Pol
sry ses FICHIERS au lieu de FILE, mis à jour en request.FILES.get ('image', False) au lieu de request.FILES ['image'], cela évitera l'exception
crodjer
3

Ce que j'ai fait pour atteindre mon objectif était de faire cela.

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

et en dessous de la méthode save () se trouve ceci.

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

donc quand je modifie certains champs mais que je ne modifie pas l'image, je mets ceci ..

Model.save("skip creating photo thumbnail")

vous pouvez remplacer le "skip creating photo thumbnail"par "im just editing the description"ou un texte plus formel.

J'espère que celui-ci vous aidera!

bonbon.langes
la source
2

Recherchez dans la base de données un enregistrement existant avec le même PK. Comparez les tailles de fichier et les sommes de contrôle des images nouvelles et existantes pour voir si elles sont identiques.

Ignacio Vazquez-Abrams
la source
1

Django 3: Remplacer les méthodes de modèle prédéfinies

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

Il est important de se rappeler d'appeler la méthode de la superclasse - c'est ça le super().save(*args, **kwargs)métier - pour s'assurer que l'objet est toujours enregistré dans la base de données. Si vous oubliez d'appeler la méthode de la superclasse, le comportement par défaut ne se produira pas et la base de données ne sera pas touchée.

panchicore
la source
0

Dans la nouvelle version, c'est comme ça:

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
la source
0

J'ai trouvé un autre moyen simple de stocker les données dans la base de données

models.py

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

Dans la base de données, je n'ai que 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 cela, j'ai créé l'instance de modèle dans views.py uniquement et mettre / enregistrer des données dans 2 variables à partir de vues uniquement.

Devendra Bhat
la source