Django. Zastąp zapisywanie modelu

140

Przed zapisaniem modelu zmieniam rozmiar obrazu. Ale jak mogę sprawdzić, czy dodano nowe zdjęcie, czy tylko zaktualizowany opis, aby móc pominąć przeskalowanie za każdym razem, gdy model jest zapisywany?

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)

Chcę przeskalować tylko po załadowaniu nowego obrazu lub aktualizacji obrazu, ale nie po zaktualizowaniu opisu.

Pol
źródło
Czy zmieniasz rozmiar do stałego rozmiaru 100x100?
bdd
3
U mogą znaleźć Django imagekit użyteczne
vikingosegundo

Odpowiedzi:

141

Kilka myśli:

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)

Nie jestem pewien, czy dobrze by działał ze wszystkimi narzędziami pseudo-auto django (przykład: ModelForm, contrib.admin itp.).

petraszd
źródło
1
Wygląda dobrze. Ale nie mogę zmienić nazwy obrazu na _image. Czy to ważne?
Pol
Ok, rozwiązałem to za pomocą db_column = 'image'. Ale to stal nie działa!
Pol
2
To bardzo ciekawa metoda… przez nie rozumiem tego w pełni. Czy możesz to wyjaśnić bardziej szczegółowo? Albo zasiać jakiś artykuł?
Pol
U mnie też to nie działa. set_image nigdy nie wywołał. Wygląda na to, że niektóre Django nie są oficjalnie obsługiwane
Ivan Borshchov
18

Sprawdź pole pk modelu. Jeśli jest brak, jest to nowy obiekt.

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)

Edycja: dodałem czek dla „obrazu” w form.changed_data. Zakłada się, że używasz witryny administratora do aktualizowania obrazów. Będziesz także musiał zastąpić domyślną metodę save_model, jak wskazano poniżej.

class ModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.save(form=form)
DM Graves
źródło
Myślę, że masz rację ... zakładając, że korzysta z witryny administratora, może zastąpić save_model w swoim AdminModel, aby przekazać formularz do zapisania i sprawdzić, czy 'image' jest w form.changed_data. Zaktualizuję, gdy tylko będę mieć czas.
DM Graves
Działa to tylko wtedy, gdy obiekt jest nowy, jak mówisz. Jeśli prześlesz nowe zdjęcie, przeskalowanie się nie uruchomi.
Jonathan,
2
"self.pk is None" nie działa, jeśli poda się id, więc: Model.objects.get_or_create (id = 234, ...) nie zadziała w tym rozwiązaniu
orzechy
7

Możesz podać dodatkowy argument za potwierdzeniem opublikowania nowego zdjęcia.
Coś jak:

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)

lub przekazać zmienną żądania

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)

Myślę, że te nie zepsują twojego zapisu, gdy zostaną po prostu wywołane.

Możesz umieścić to w swoim admin.py, aby działało również z witryną administracyjną (dla drugiego z powyższych rozwiązań):

class ModelAdmin(admin.ModelAdmin):

    ....
    def save_model(self, request, obj, form, change): 
        instance = form.save(commit=False)
        instance.save(request=request)
        return instance
crodjer
źródło
mówi mi, że: obiekt „WSGIRequest” nie ma atrybutu „PLIK”
Pol
sry jego FILES zamiast FILE, zaktualizowane do request.FILES.get ('image', False) zamiast request.FILES ['image'], pozwoli to uniknąć wyjątku
crodjer
3

Aby osiągnąć cel, zrobiłem to ...

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

a poniżej metody save () jest to ...

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

więc kiedy edytuję niektóre pola, ale nie edytuję obrazu, umieszczam to ...

Model.save("skip creating photo thumbnail")

można wymienić "skip creating photo thumbnail"z "im just editing the description"lub bardziej formalne tekstu.

Mam nadzieję, że ten pomoże!

bonbon.langes
źródło
2

Zapytaj bazę danych o istniejący rekord o tej samej PK. Porównaj rozmiary plików i sumy kontrolne nowych i istniejących obrazów, aby sprawdzić, czy są takie same.

Ignacio Vazquez-Abrams
źródło
-1

W nowej wersji wygląda to tak:

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
źródło
-1

Znalazłem inny prosty sposób na przechowywanie danych w bazie danych

models.py

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

W bazie danych mam tylko 2 zmienne

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

W tym utworzyłem instancję modelu tylko w views.py i umieszczając / zapisując dane w 2 zmiennych tylko z widoków.

Devendra Bhat
źródło