ジャンゴ。モデルの保存を上書き


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
Uは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の一部のようです
Ivan Borshchov

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)

私はあなたが正しいと思います...彼が管理サイトを使用していると仮定すると、彼は彼のAdminModelのsave_modelをオーバーライドしてフォームを渡して保存し、「image」がform.changed_dataにあるかどうかを確認できます。時間になり次第更新します。
DM Graves

これは、オブジェクトが新しい場合にのみ機能します。新しい画像をアップロードした場合、再スケーリングはトリガーされません。
ジョナサン

2
idを指定した場合、「self.pk is None」は機能しないため、Model.objects.get_or_create(id = 234、...)は、このソリューションでは機能しません
nuts

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に入れて、管理サイトでも機能するようにすることができます(上記の2番目のソリューションの場合)。

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

FILEの代わりにFILESを使用し、request.FILES ['image']の代わりにrequest.FILES.get( 'image'、False)に更新すると、例外が回避されます
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"以上の正式なテキスト。

これが役に立てば幸い!



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

データをデータベースに保存するもう1つの簡単な方法を見つけました

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つの変数にデータを配置/保存しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.