Django视图不会通过AJAX保存上传的图像。

huangapple go评论74阅读模式
英文:

Django view won't save image uploaded through AJAX

问题

I'm having a problem with my tweet image not saving to my model when my tweet form is submitted. The other content of the tweet such as the tweet itself has no problem saving but the image is where the issue lies. I am submitting my form using AJAX, and making the appropriate call to the view to save the tweet content to the Tweet model. When I print the values of request.FILES and request.POST, this is what I get ('test' is what I have inputted for my tweet field for demonstration):

views.py

@csrf_exempt
def post_tweet(request):
    if request.method == "POST":
        print(request.FILES, request.POST)

        # Get contents of form
        tweet = request.POST.get("tweet", "").strip()

        # This doesn't capture the image passed.
        image = request.FILES.get("tweet-picture")

        # Save the tweet to the model
        new_tweet = Tweet.objects.create(tweet=tweet, user=request.user, image=image)
        new_tweet.save()

        return JsonResponse({"message": "Tweet created successfully."}, status=201)
    else:
        return JsonResponse({"error": "POST request required."}, status=400) 

JS code that handles request (Within my DOMContentLoaded Listener)

// When the form is submitted
  const tweetForm = document.querySelector("#tweet-form");
  tweetForm.addEventListener('submit', function(event) {

    event.preventDefault();
    // Stops other event listeners of the same type of being called
    event.stopImmediatePropagation();

    const tweetInput = document.getElementById("post-content");
    const tweet = tweetInput.value;

    let tweetImage = "";
    try {
      const tweetImageElement = document.querySelector("#tweet-picture-preview img");
      tweetImage = tweetImageElement.getAttribute('src');
      console.log(tweetImage);
    } catch {
      console.log("No tweet image provided.");
    }

    const userNameInput = document.querySelector("#tweet-username");
    const username = userNameInput.value;

    if (tweet.trim().length > 0) {
      const csrftoken = getCookie('csrftoken');
      const formData = new FormData(tweetForm);
      fetch("/post_tweet/", {
        method: "POST",
        body: formData,
        headers: {
          'X-CSRFToken': csrftoken,
        },
      })
      .then(response => response.json())
      .then(data => {
        console.log(data.message);
        console.log(tweetImage);
        addPostToPage(tweet, tweetImage, username);

        // Clear the tweet form
        clearPostSection();
      })
      .catch(error => {
        console.log(error);
      });
    }
  }); 

It is important to note that with the code above, the tweetImage variable is able to properly retrieve the image that was selected by the user but is fully encrypted... So I'm not sure if that entirely counts or if that could be the issue potentially.

Django template

<form id="tweet-form" method="post" enctype="multipart/form-data">

    <!-- To display tweet image preview and delete functionality -->
    <div id="tweet-picture-preview">
        <div class="image-container">
        </div>
    </div>

    <div class="post-section-row">
        <div class="error-message"></div>
        <div class="tweet-actions">
            <label for="tweet-picture" title="Upload Picture">
                <span class="material-symbols-outlined image-button">photo_library</span>
                <span class="tooltiptext">Upload Picture</span>
            </label>        
            <input type="file" id="tweet-picture" name="tweet-picture" class="file-input" accept="image/jpeg, image/png, image/gif, image/jpg" onchange="previewTweetImage(event)">                
            <input type="submit" id="post-button" value="Post">
        </div>
    </div>
</form>

Below is also my urls.py snippet, which I believe is fine, but if something is off let me know!

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path("", views.index, name="index"),
    path("login", views.login_view, name="login"),
    path("logout", views.logout_view, name="logout"),
    path("register", views.register, name="register"),
    path("profile_settings", views.change_profile, name="change_profile"),

    # API Routes (to handle saving, retrieving tweet data)
    path("post_tweet/", views.post_tweet, name="post_tweet"),
] 

If you require any other information please let me know! The image prior to some changes was saving properly to the model, but I am entirely not sure what went wrong as I was working on other features for my app.

英文:

I'm having a problem with my tweet image not saving to my model when my tweet form is submitted. The other content of the tweet such as the tweet itself has no problem saving but the image is where the issue lies. I am submitting my form using AJAX, and making the appropriate call to the view to save the tweet content to the Tweet model. When I print the values of request.FILES and request.POST, this is what I get ('test' is what I have inputted for my tweet field for demonstration):

&lt;MultiValueDict: {}&gt; &lt;QueryDict: {&#39;tweet&#39;: [&#39;test&#39;]}&gt;

views.py

def post_tweet(request):
    if request.method == &quot;POST&quot;:
        print(request.FILES, request.POST)

        # Get contents of form
        tweet = request.POST.get(&quot;tweet&quot;, &quot;&quot;).strip()

        # This doesn&#39;t capture the image passed.
        image = request.FILES.get(&quot;tweet-picture&quot;)

        # Save the tweet to the model
        new_tweet = Tweet.objects.create(tweet=tweet, user=request.user, image=image)
        new_tweet.save()

        return JsonResponse({&quot;message&quot;: &quot;Tweet created successfully.&quot;}, status=201)
    else:
        return JsonResponse({&quot;error&quot;: &quot;POST request required.&quot;}, status=400) 

JS code that handles request (Within my DOMContentLoaded Listener)

  const tweetForm = document.querySelector(&quot;#tweet-form&quot;);
  tweetForm.addEventListener(&#39;submit&#39;, function(event) {

    event.preventDefault();
    // Stops other event listeners of the same type of being called
    event.stopImmediatePropagation();

    const tweetInput = document.getElementById(&quot;post-content&quot;);
    const tweet = tweetInput.value;

    let tweetImage = &quot;&quot;;
    try {
      const tweetImageElement = document.querySelector(&quot;#tweet-picture-preview img&quot;);
      tweetImage = tweetImageElement.getAttribute(&#39;src&#39;);
      console.log(tweetImage);
    } catch {
      console.log(&quot;No tweet image provided.&quot;);
    }

    const userNameInput = document.querySelector(&quot;#tweet-username&quot;);
    const username = userNameInput.value;

    if (tweet.trim().length &gt; 0) {
      const csrftoken = getCookie(&#39;csrftoken&#39;);
      const formData = new FormData(tweetForm);
      fetch(&quot;/post_tweet/&quot;, {
        method: &quot;POST&quot;,
        body: formData,
        headers: {
          &#39;X-CSRFToken&#39;: csrftoken,
        },
      })
      .then(response =&gt; response.json())
      .then(data =&gt; {
        console.log(data.message);
        console.log(tweetImage);
        addPostToPage(tweet, tweetImage, username);

        // Clear the tweet form
        clearPostSection();
      })
      .catch(error =&gt; {
        console.log(error);
      });
    }
  }); 

It is important to note that with the code above, the tweetImage variable is able to properly retrieve the image that was selected by the user but is fully encrypted... So I'm not sure if that entirely counts or if that could be the issue potentially.

Django template

&lt;form id=&quot;tweet-form&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;

    &lt;!-- To display tweet image preview and delete functionality --&gt;
    &lt;div id=&quot;tweet-picture-preview&quot;&gt;
        &lt;div class=&quot;image-container&quot;&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class=&quot;post-section-row&quot;&gt;
        &lt;div class=&quot;error-message&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;tweet-actions&quot;&gt;
            &lt;label for=&quot;tweet-picture&quot; title=&quot;Upload Picture&quot;&gt;
                &lt;span class=&quot;material-symbols-outlined image-button&quot;&gt;photo_library&lt;/span&gt;
                &lt;span class=&quot;tooltiptext&quot;&gt;Upload Picture&lt;/span&gt;
            &lt;/label&gt;        
            &lt;input type=&quot;file&quot; id=&quot;tweet-picture&quot; name=&quot;tweet-picture&quot; class=&quot;file-input&quot; accept=&quot;image/jpeg, image/png, image/gif, image/jpg&quot; onchange=&quot;previewTweetImage(event)&quot;&gt;                
            &lt;input type=&quot;submit&quot; id=&quot;post-button&quot; value=&quot;Post&quot;&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/form&gt;

Below is also my urls.py snippet, which I believe is fine, but if something is off let me know!

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path(&quot;&quot;, views.index, name=&quot;index&quot;),
    path(&quot;login&quot;, views.login_view, name=&quot;login&quot;),
    path(&quot;logout&quot;, views.logout_view, name=&quot;logout&quot;),
    path(&quot;register&quot;, views.register, name=&quot;register&quot;),
    path(&quot;profile_settings&quot;, views.change_profile, name=&quot;change_profile&quot;),

    # API Routes (to handle saving, retrieving tweet data)
    path(&quot;post_tweet/&quot;, views.post_tweet, name=&quot;post_tweet&quot;),
] 

If you require any other information please let me know! The image prior to some changes was saving properly to the model, but I am entirely not sure what went wrong as I was working on other features for my app.

答案1

得分: 0

不要回答我要翻译的问题。以下是要翻译的内容:

"Instead of passing in the tweetForm to the FormData, I manually added in the fields (tweet and tweet-image) while adjusting for the value of the input field itself, not the source of the image. Here is my updated code with the solution which allowed me to save images to the model asynchronously.

views.py

@csrf_exempt
def post_tweet(request):
    if request.method == "POST":
        print(request.FILES, request.POST)

        # Get contents of form
        tweet = request.POST.get("tweet", "").strip()
        image = request.FILES.get("tweet_image")

        # Save the tweet to the model
        new_tweet = Tweet.objects.create(tweet=tweet, user=request.user, image=image)
        new_tweet.save()

        # Generate the URL for the uploaded image
        if image:
            image_url = settings.MEDIA_URL + str(image)
        else:
            image_url = None

        return JsonResponse({"message": "Tweet created successfully.", "image_url": image_url}, status=201)
    else:
        return JsonResponse({"error": "POST request required."}, status=400)

posts.js

const tweetForm = document.querySelector("#tweet-form");
  tweetForm.addEventListener('submit', function(event) {

    event.preventDefault();
    // Stops other event listeners of the same type of being called
    event.stopImmediatePropagation();

    const tweetInput = document.getElementById("post-content");
    const tweet = tweetInput.value;

    const tweetImageElement = document.querySelector("#tweet-picture");

    // Access the selected file and if there isn't any files, an empty string
    const tweetImageFile = tweetImageElement.files[0] ? tweetImageElement.files[0]: "";

    const userNameInput = document.querySelector("#tweet-username");
    const username = userNameInput.value;

    if (tweet.trim().length > 0) {
      const csrftoken = getCookie('csrftoken');
      const formData = new FormData();
      formData.append('tweet', tweet);  // Add tweet content to FormData
      formData.append('tweet_image', tweetImageFile);  // Add image file to FormData
  
      fetch("/post_tweet/", {
        method: "POST",
        body: formData,
        headers: {
          'X-CSRFToken': csrftoken,
        },
      })
      .then(response => response.json())
      .then(data => {
        console.log(tweetImageFile);

        if (tweetImageFile) {
          addPostToPage(tweet, `/media/tweet-pictures/${tweetImageFile.name}`, username);
        } else {
          addPostToPage(tweet, "", username);
        }

        clearPostSection();
        console.log(data.message);
      })
      .catch(error => {
        console.log(error);
      });
    }
  });

(Note: The code you provided contains HTML entities for double quotes (") and other characters. I've replaced them with actual double quotes and characters in the translated code.)"

英文:

Instead of passing in the tweetForm to the FormData, I manually added in the fields (tweet and tweet-image) while adjusting for the value of the input field itself, not the source of the image. Here is my updated code with the solution which allowed me to save images to the model asynchronously.

views.py

@csrf_exempt
def post_tweet(request):
if request.method == &quot;POST&quot;:
print(request.FILES, request.POST)
# Get contents of form
tweet = request.POST.get(&quot;tweet&quot;, &quot;&quot;).strip()
image = request.FILES.get(&quot;tweet_image&quot;)
# Save the tweet to the model
new_tweet = Tweet.objects.create(tweet=tweet, user=request.user, image=image)
new_tweet.save()
# Generate the URL for the uploaded image
if image:
image_url = settings.MEDIA_URL + str(image)
else:
image_url = None
return JsonResponse({&quot;message&quot;: &quot;Tweet created successfully.&quot;, &quot;image_url&quot;: image_url}, status=201)
else:
return JsonResponse({&quot;error&quot;: &quot;POST request required.&quot;}, status=400)

posts.js

const tweetForm = document.querySelector(&quot;#tweet-form&quot;);
tweetForm.addEventListener(&#39;submit&#39;, function(event) {
event.preventDefault();
// Stops other event listeners of the same type of being called
event.stopImmediatePropagation();
const tweetInput = document.getElementById(&quot;post-content&quot;);
const tweet = tweetInput.value;
const tweetImageElement = document.querySelector(&quot;#tweet-picture&quot;);
// Access the selected file and if there isn&#39;t any files, an empty string
const tweetImageFile = tweetImageElement.files[0] ? tweetImageElement.files[0]: &quot;&quot;;
const userNameInput = document.querySelector(&quot;#tweet-username&quot;);
const username = userNameInput.value;
if (tweet.trim().length &gt; 0) {
const csrftoken = getCookie(&#39;csrftoken&#39;);
const formData = new FormData();
formData.append(&#39;tweet&#39;, tweet);  // Add tweet content to FormData
formData.append(&#39;tweet_image&#39;, tweetImageFile);  // Add image file to FormData
fetch(&quot;/post_tweet/&quot;, {
method: &quot;POST&quot;,
body: formData,
headers: {
&#39;X-CSRFToken&#39;: csrftoken,
},
})
.then(response =&gt; response.json())
.then(data =&gt; {
console.log(tweetImageFile);
if (tweetImageFile) {
addPostToPage(tweet, `/media/tweet-pictures/${tweetImageFile.name}`, username);
} else {
addPostToPage(tweet, &quot;&quot;, username);
}
clearPostSection();
console.log(data.message);
})
.catch(error =&gt; {
console.log(error);
});
}
});

huangapple
  • 本文由 发表于 2023年6月22日 02:38:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526225.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定