【问题标题】:Passing Django model properties to JavaScript with the Fetch API使用 Fetch API 将 Django 模型属性传递给 JavaScript
【发布时间】:2021-05-24 20:05:13
【问题描述】:

我正在执行一项任务,以使用 fetch API 执行一些我们可以让 Python 在我们的视图中使用 JavaScript 执行的常规操作,例如添加记录或查询数据库。我遇到的一个问题是传递我们在 Django 中看到的普通属性,比如用户或用户名,当我使用 fetch API 从 sql 数据库中提取它时,它只是显示为文字用户 ID。使用我现在编写的视图、html 和 JavaScript,我将如何使用 JavaScript 中的 fetch 提取用户名,我通常可以在 Django 控制台中使用变量或使用 print 语句获取用户名,而不仅仅是查看用户 ID从数据库。我觉得我错过了一步,我只是没有看到它。

网址

app_name = "network"
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"),

    # API Routes
    path("addpost", views.post, name="post"),
    path("<str:navbar_item>", views.viewposts, name="viewposts"),
]

models.py

class User(AbstractUser):
    pass


class Profile(models.Model):
    user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
    bio = models.TextField(null=True, blank=True)
    # pics
    website = models.CharField(max_length=225, null=True, blank=True)
    follower = models.ManyToManyField(
        User, blank=True, related_name="followed_user")  # user following this profile
    # profile user that follows this profile
    following = models.ManyToManyField(
        User, blank=True, related_name="following_user")

    def __str__(self):
        return f"{self.user}'s' profile id is {self.id}"

    def following_users(self):
        for username in self.following:
            return username

    def get_absolute_url(self):
        return reverse("network:profile-detail", args=[str(self.id)])


class Post(models.Model):
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="post_user")
    body = models.TextField(max_length=1000)
    timestamp = models.DateTimeField(auto_now_add=True)
    likes = models.ManyToManyField(User, blank=True, related_name="post_likes")

    def __str__(self):
        return f"{self.created_by} posted {self.body}"

    def get_absolute_url(self):
        return reverse("network:post-detail", args=[str(self.id)])

    def total_likes(self):
        return self.likes.count()

    class Meta:
        ordering = ["-timestamp"]

views.py

def index(request):

    if request.user.is_authenticated:
        return render(request, "network/index.html", {})
    else:
        return HttpResponseRedirect(reverse("network:login"))


@login_required
def post(request):

    # Composing a new post must be done via POST
    if request.method != "POST":
        return JsonResponse({"error": "You must POST your request."}, status=404)

    try:
        data = json.loads(request.body)
        body = data.get("body", "")
        user = request.user
        print(user)
        post = Post(created_by=user, body=body)
        # post = Post(created_by=Profile.objects.get(user=user), body=body)
        post.save()
    except AttributeError:
        return JsonResponse({"error": "AttributeError thrown."}, status=500)

    return JsonResponse({"message": "Post created."}, status=201)


@login_required
def viewposts(request, navbar_item):

    if navbar_item == "viewposts":
        posts = Post.objects.all()
        posts = posts.order_by("-timestamp")
        json_post = serialize("json", posts)
        print(posts)
        return HttpResponse(json_post, content_type="application/json")
    else:
        return JsonResponse({"error": "Invalid page."}, status=400)

index.html

{% extends "network/layout.html" %}
{% load static %}
{% block body %}
    <div class="container p-5">
        {% if error %}
            {{ error }}
        {% endif %}
        <h1 class="display-4">All Posts</h1>
        <div class="form-group border rounded p-4">
        <h2 class="diplay-3">New Post</h2>
            <form id="addpost" class="form-group pt-5">
                {% csrf_token %}
                <div class="form-group">
                    <textarea class="form-control" id="body" placeholder="Add post here..."></textarea>
                </div>
                <input type="submit" class="btn btn-primary"/>
            </form>
        </div>
        
        <div id="all-posts" class="all-posts">
        </div>
    </div>

{% endblock %}

{% block script %}
    <script src="{% static 'network/main.js' %}"></script>
{% endblock %}

JavaScript

// Post on index page # API Routes /addpost
const addPost = () => {

    const addPostUrl = '/addpost';
    const csrftoken = getCookie('csrftoken');
    const body = document.querySelector('#body').value;
    // body needs to be passed into an object before using the stringify method
    const bodyObject = { body };

        fetch(addPostUrl, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRFToken': csrftoken,
        },
        body: JSON.stringify(bodyObject)
    })
    .then(response => response.json())
    .then(result => {
        console.log(result);
    })
    .catch(error => {
        console.log(error);
    });
    return false;
};

// Load posts in index page  # API Routes /navbar_item
function loadPosts(navItem, event) {
    preventPageLoad(event);
    const postUrl = `/${navItem}`;
    
    // Send a GET request to the URL to retrieve all posts
    fetch(postUrl)
    .then(response => response.json())
    .then(data => {
        data.forEach(post => {
            const { fields } = post;
            const allPostsContainer = document.querySelector("#all-posts");
            const element = document.createElement('div');
            const postId = `#post-${fields.id}`;
            element.style.textDecoration = 'none';
            element.classList.add('HoverClass1');
            element.setAttribute('id', `post-${fields.id}`);
            element.classList.add('d-flex', 'flex-column' ,'justify-content-between', 'p-4', 'm-3', 'lead', 'border', 'rounded');
            element.style.color = '#000000';
            element.innerHTML = 
                                                                  // This is returning an id
                `<div class="bd-highlight font-weight-bolder mr-5">${fields.created_by}</div>
                <div class="bd-highlight">${fields.timestamp}</div>
                <div class="flex-fill bd-highlight">${fields.body}</div>`;
                

            console.log(fields);
             
            allPostsContainer.append(element);
            
            const linePost = document.querySelector(postId);
            linePost.addEventListener('click', (event) => {
                console.log(event);
            });
        });
    })
    .catch(error => {
        console.log(error);
    });
    return false;
}

图像显示了我在 Django 中的管理控制台与浏览器控制台的对比,以及 JavaScript 中提取的内容。您会在管理控制台中看到我们可以查看用户名,但在浏览器控制台中,我得到的只是带有 fetch 的用户 ID。

【问题讨论】:

    标签: javascript python django django-templates


    【解决方案1】:

    我想出了如何做到这一点。我在 Post 模型中添加了一个序列化方法来将这些属性转换为 JSON。

    def serialize(self):
            return {
                'id': self.id,
                'created_by': self.created_by.username,
                'body': self.body,
                'timestamp': self.timestamp.strftime('%b %-d %Y, %-I:%M %p'),
                'likes': self.total_likes()
            }
    

    然后在 views.py 中,在我的 viewposts 函数中,我使用 JsonResponse 而不是我的 HttpResponse,并将模型的序列化方法作为参数传递。

    @login_required
    def viewposts(request, navbar_item):
    
        if navbar_item == "viewposts":
            posts = Post.objects.all()
            posts = posts.order_by("-timestamp")
            return JsonResponse([post.serialize() for post in posts], safe=False)
        else:
            return JsonResponse({"error": "Invalid page."}, status=400)
    

    这让我不必解构我的 JavaScript 文件中的任何内容。因此,我可以使用点符号直接从 fetch 中的数据模型中提取查询中的任何属性。

    【讨论】:

      猜你喜欢
      • 2020-11-02
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 2017-03-23
      • 1970-01-01
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多