Джанго. Отменить сохранение для модели


134

Перед сохранением модели я изменяю размер изображения. Но как я могу проверить, добавлено ли новое изображение или просто обновлено описание, чтобы я мог пропустить изменение масштаба каждый раз при сохранении модели?

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)

Я хочу изменить масштаб только при загрузке нового изображения или обновлении изображения, но не при обновлении описания.


Вы изменяете размер до фиксированного 100x100?
bdd

3
Вы можете найти django-imagekit полезным
vikingosegundo

Ответы:


135

Некоторые мысли:

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)

Не уверен, что это будет хорошо работать со всеми псевдо-автоматическими инструментами django (пример: ModelForm, contrib.admin и т. Д.).


1
Выглядит хорошо. Но я не могу переименовать изображение в _image. Это важно?
Pol

Хорошо, я решил это с помощью db_column = 'image'. Но стальной не работает!
Pol

1
Это очень интересный метод ... я не понимаю его полностью. Не могли бы вы объяснить это более подробно? Или статью сеять?
Pol

У меня тоже не работает. set_image никогда не вызывался. Похоже, это какой-то Django официально не поддерживается
Иван Борщов

16

Проверьте поле pk модели. Если это None, то это новый объект.

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)

Изменить: я добавил проверку на «изображение» в form.changed_data. Это предполагает, что вы используете сайт администратора для обновления изображений. Вам также придется переопределить метод save_model по умолчанию, как указано ниже.

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

Я думаю, вы правы ... предполагая, что он использует сайт администратора, он может переопределить save_model в своей AdminModel, чтобы передать форму для сохранения и проверить, находится ли 'image' в form.changed_data. Я обновлюсь, как только у меня будет время.
DM Graves,

Это работает, только если объект новый, как вы говорите. Если вы загрузите новое изображение, изменение масштаба не сработает.
Джонатан

2
«self.pk is None» не работает, если указан идентификатор, поэтому: Model.objects.get_or_create (id = 234, ...) не будет работать в этом решении
орехи

6

Вы можете предоставить дополнительный аргумент для подтверждения публикации нового изображения.
Что-то вроде:

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)

или передать переменную запроса

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)

Я думаю, что при простом вызове они не сломают ваш сейв.

Вы можете поместить это в свой admin.py, чтобы он работал и с сайтом администратора (для второго из вышеперечисленных решений):

class ModelAdmin(admin.ModelAdmin):

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

он сообщает мне, что: объект 'WSGIRequest' не имеет атрибута 'FILE'
Pol

попробуйте его ФАЙЛЫ вместо ФАЙЛА, обновив на request.FILES.get ('image', False) вместо request.FILES ['image'], это позволит избежать исключения
Crodjer

3

Для достижения цели я сделал это ..

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

а ниже метод save () это ..

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

поэтому, когда я редактирую некоторые поля, но не редактирую изображение, я помещаю это ..

Model.save("skip creating photo thumbnail")

вы можете заменить "skip creating photo thumbnail"с "im just editing the description"или более формальным текстом.

Надеюсь, это поможет!


2

Запросите в базе данных существующую запись с тем же PK. Сравните размеры файлов и контрольные суммы новых и существующих изображений, чтобы увидеть, совпадают ли они.


1

Django 3: переопределение предопределенных методов модели

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

Важно не забыть вызвать метод суперкласса - это то super().save(*args, **kwargs)дело, - чтобы гарантировать, что объект по-прежнему сохраняется в базе данных. Если вы забудете вызвать метод суперкласса, поведения по умолчанию не произойдет, и база данных не будет затронута.


0

В новой версии это так:

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

Я нашел еще один простой способ хранить данные в базе данных

models.py

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

В базе данных всего 2 переменные

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

В этом случае я создал экземпляр модели только в views.py и поместил / сохранил данные в 2 переменные только из представлений.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.