首页 > 解决方案 > 用 JS 和 Django 修改一篇文章?

问题描述

我目前正在研究 CS50Web 网络项目 4,我一直在编辑显示的许多帖子中的一个帖子。

我有一个显示用户完成的所有帖子的视图。

def profile(request, username):
    if request.method == "GET":
        user = User.objects.filter(username=username)
        profile = Profile.objects.filter(user=user[0]).get()
        posts = Post.objects.filter(user=user[0]).order_by('-publish_date')
        return render(
            request,
            'network/profile.html',
            {
                'posts': page,
                'profile': profile,
            }
        )

并显示在 html 模板中。

{% for post in posts %}
<div class="card text-center">
    <div class="card-header">
        <a href="{% url 'profile' post.user %}"> {{ post.user }} </a>
    </div>
    <div class="card-body">
      <h5 class="card-title">{{ post.content }}</h5>
      <p class="card-text">{{ post.num_likes }}</p>
      <a href="#" class="btn btn-primary" onclick="editpost()"> Edit </a>
    </div>
    <div class="card-footer text-muted">
        {{ post.publish_date }}
    </div>
</div>
<br>
{% endfor %}

我知道我需要一个函数来使用 JS 从该特定表单中更改<h5>标签和<p>标签,但我知道如何仅从一个帖子中获取它,而不是从 Django 模板引擎生成的所有帖子中获取它。

一旦我可以选择它们,我会将它们的信息复制到一个 var 中并更改样式,这样显示就不会像创建介绍一样,我将介绍来自 var 的数据并允许用户修改它们。

然后将创建一个新的<a>was 供用户保存更改。目前,我正在考虑使用 Ajax 将数据发送回服务器,但如果有更好的建议,我愿意接受建议。

我会上传数据库的模型,但我认为这没有必要。非常感谢任何帮助或指导。

标签: javascriptdjango

解决方案


您在模板中使用的 JavaScript 提供了有关如何为用户 (ie for post in posts) 访问每个帖子以及如何设置该帖子的h5元素 (ie post.content) 和p元素 (ie post.num_likes) 中出现的值的线索。

要更新视图中的所有这些,您可以执行以下操作:

posts = Post.objects.filter(user=user[0]).order_by('-publish_date');

for (let post in posts){
  post.content = my_new_content;
  post.num_likes = my_new_num_likes;
}

return render( // etc...

或者,如果您想保持基础值不变,只更新 DOM(模板)值,您只需将模板更新代码更改为:

  <h5 class="card-title">{{ my_new_content }}</h5>
  <p class="card-text">{{ my_new_num_likes }}</p>

我对这部分感到困惑:“...更改样式以使显示不存在以及创建介绍是我将介绍数据...”,但是如果您在渲染后尝试访问 DOM 元素,在 MDN 上记录了几种有用的相关技术。

对于您的情况,如果所有卡片都出现在同一页面上,您可能会执行以下操作:

const
  // Defines an array to hold values found in the DOM
  oldCardInfoArray = [],

  // Collects references to all card elements on the page
  cards = document.getElementsByClassName("card"),

  // Converts cards to an array, and gets only those cards whose user matches `post.user`
  //   (Assumes this code has access to some `post` object with a `user` property)
  userCards = (Array.from(cards)).filter( 
    (card) => card.querySelector("a").textContent.trim() == post.user)
  );

// Loops through the userCards
for(let userCard of userCards){
  const
    // Identifies title and text of each card (as `oldTitle` and `oldText`, respectively) 
    cardTitleElement = userCard.querySelector(".card-title"),
    cardTextElement = userCard.querySelector(".card-text"),
    oldTitle = cardTitleElement.textContent,
    oldText = cardTextElement.textContent,

    // Makes an `oldCardInfo` object with two properties, and adds it to the array
    oldCardInfo = { oldTitle: oldTitle, oldText: oldText };
  oldCardInfoArray.push(oldCardInfo);
}

// Now the array is populated, and we can do something with its contents
for(let card of oldCardInfoArray){
  const oldTitle = card.oldTitle;
  const oldText = card.oldText;
  // Prints the values from each card to the browser console
  //   (or you could send them to the server, or whatever)
  console.log("title: " + oldTitle + ", text: " + oldText);
}

显然,所有这些代码都未经测试,但它至少应该给你一些想法。


编辑:
作为对您的评论的回应,要选择包含单击按钮的卡片,您可以将这样的代码放入您的editPost函数中:

const card = this.closest(".card");

因此,现在,您将能够仅使用卡片中用户与之交互的那些元素,而不是循环遍历卡片(就像cardTitleElement上面的 with 一样)。

或者,或者,您可以将内联事件处理程序(onclick = editPost()在模板中)替换为事件侦听器,或者 1)在<script>模板底部的元素内或 2)直接在现有 JavaScript 代码中(尽管我不确定哪个Django 的一部分处理了第二种方法)。它可能看起来像:

document.addEventListener("click", editPost);

function editPost(event){ // Listener sees triggering event
  const clickedThing = event.target; // Event has useful properties
  const userCard = clickedThing.closest(".card");
  if(userCard){ // Makes sure button has a `card` ancestor before proceeding

    // Now, with the correct card identified, we can collect values from it
    const cardTitleElement = userCard.querySelector(".card-title");
    const cardTextElement = userCard.querySelector(".card-text");
      // ...etc, as described above
  }
}

推荐阅读