[Answered ]-Django set image delete old reference and prevent delete default

1👍

Honestly, I did not test your function to say what is wrong with it. Instead I implemented it in my own way taking your model as a base. If you really want a set_image(instance, attr, file) function, you can adapt it from this answer create_profile_ajax at views.py.

settings.py

DEFAULT_IMAGE_URL = 'profile/default.jpg'

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = ProcessedImageField(
        default=settings.DEFAULT_IMAGE_URL,
        upload_to='avatars',
        processors=[ResizeToFill(100, 50)],
        format='JPEG',
        options={'quality': 60},
        blank=True,
        null=True
    )

    @staticmethod
    def default_image_absolute_url():
        return settings.MEDIA_URL + settings.DEFAULT_IMAGE_URL
    
    @staticmethod
    def default_image_url():
        return settings.DEFAULT_IMAGE_URL

forms.py

class ProfileForm(forms.ModelForm):

    class Meta:
        model = Profile
        fields = ['image']

views.py

@login_required
def create_profile(request):
    form = ProfileForm()
    return render(request, 'profile/create.html', {'form': form})


def create_profile_ajax(request):
    image = request.FILES.get('image')
    profile, created = Profile.objects.get_or_create(user=request.user)

    if image:
        if profile.image.url == Profile.default_image_absolute_url():
            profile.image = image
        else:
            profile.image.delete()
            profile.image = image
    else:
        profile.image = Profile.default_image_url()
    
    profile.save()
    profile.refresh_from_db()

    return JsonResponse({'new_image_url': profile.image.url})

profile/create.html (csrf with ajax)

{% extends 'base.html' %}

{% block content %}
{{form.as_p}}
<input type="submit" value="Create" onclick="sendProfile()">

<img src="{{request.user.profile.image.url}}" 
    id="thumb" 
    width="500" 
    height="600" 
    {% if not request.user.profile.image %} hidden {% endif %} 
    style="object-fit: contain;">


<script>
    function getCookie(name) {
        ...
    }

    function sendProfile() {
        const csrftoken = getCookie('csrftoken');
        var input = document.getElementById('id_image');
        var data = new FormData()
        data.append('image', input.files[0])

        fetch('/your/ajax/url/', {
        method: 'POST',
        headers: {
            'X-CSRFToken': csrftoken
        },
        body: data
        })
        .then((response) => response.json())
        .then((data) => {
            var thumb = document.getElementById('thumb');
            thumb.src = data.new_image_url;
            thumb.hidden = false;
            input.value = '';
        });
    }
</script>
{% endblock %}

quotting FormData documentation:

When using FormData to submit POST requests using XMLHttpRequest or
the Fetch_API with the multipart/form-data Content-Type (e.g. when
uploading Files and Blobs to the server), do not explicitly set the
Content-Type header on the request.

👤Niko

Leave a comment