简体   繁体   中英

Passing Django model properties to JavaScript with the Fetch API

I'm working on an assignment to use the fetch API to do some of the normal things we would have Python do in our views with JavaScript such as adding records or querying the database. One issue I'm running across is passing the normal properties we would see in Django, say a user or username, where it just shows up as a literal user id when I pull it from the sql database with the fetch API. With the views, html and JavaScript I have written now, how would I go about pulling the username with fetch in JavaScript that I can normally grab with a variable or view with a print statement in the Django console, instead of just viewing the user id from the database. I feel like I'm missing a step and I'm just not seeing it.

urls

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;
}

Images showing my admin console in Django versus the browser console and what fetch is pulling in JavaScript. You'll see in the admin console we can view the username, but in the browser console all I'm getting is the user id with fetch.

后管理员

javascript_console

I figured out how to do this. I added a serialize method to the Post model to convert these properties to 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()
        }

Then in views.py, in my viewposts function, instead of my the HttpResponse, I used JsonResponse and passed the model's serialize method as an argument.

@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)

This allowed me to not have to deconstruct anything in my JavaScript file. So I could pull any attributes from my query using dot notation directly off of the data model in fetch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM