Django项目中如何为JavaScript动态加载的博客内容应用原有HTML卡片样式?
I implemented a "Load More" button on my blog page using JavaScript to dynamically load blog content, but I can't figure out how to make the dynamically loaded content use the original HTML card styling.
My original HTML template (Django):
{% for filt in object_list %} <div class="card mb-4"> {% if not filt.blog_cover_image %} <img class="img-fluid rounded" style="max-height:1000px;max-width:1200px;" src="https://via.placeholder.com/900x300" alt="..." /> {% else %} <img class="img-fluid rounded" style="max-height:1000px;max-width:1200px;" src="{{ filt.blog_cover_image.url }}" alt="..." /> {%endif%} <div class="card-body"> <h2 class="card-title"><a href="{% url 'blog:blog-detail' filt.slug %}">{{filt.title}}</a></h2> <p class="card-text">{{filt.body|striptags|safe|slice:":250" }}</p> <a class="btn btn-primary" href="{% url 'blog:blog-detail' filt.slug %}">Read More →</a> </div> <div class="card-footer text-muted"> Posted on ({{filt.created_at}}) <div class="author">{{filt.author.first_name}} {{filt.author.last_name}} {% if user.is_authenticated %}{% if user.id == blog.author.id or user.is_superuser %}<a href="{% url 'blog:blog-update' filt.slug %}"><b>(Edit Blog)</b></a> <a href="{% url 'blog:blog-delete' filt.slug %}"><b>(Delete Blog)</b></a>{% endif %}{% endif %}</div> </div> </div> {% endfor %}
HTML structure for "Load More" functionality:
<div id="posts-box"></div> <div id="spinner-box" class="not-visible"> <div class="spinner-border text-primary" role="status"></div> </div> <div id="loading-box"> <button class="btn btn-primary" id="load-btn">Load more</button> </div>
My JavaScript code:
const postsBox = document.getElementById('posts-box') console.log(postsBox) const spinnerBox = document.getElementById('spinner-box') const loadBtn = document.getElementById('load-btn') const loadBox = document.getElementById('loading-box') let visible = 3 const handleGetData = () => { $.ajax({ type: 'GET', url: `/posts-json/${visible}/`, success: function(response){ maxSize = response.max const data = response.data spinnerBox.classList.remove('not-visible') setTimeout(()=>{ spinnerBox.classList.add('not-visible') data.map(post=>{ console.log(post.id) postsBox.innerHTML += `<div class="card mb-4"> ${post.title} <br> ${post.body} </div>` }) if(maxSize){ console.log('done') loadBox.innerHTML = "<h4>No more posts to load</h4>" } }, 500) }, error: function(error){ console.log(error) } }) } handleGetData() loadBtn.addEventListener('click', ()=>{ visible += 3 handleGetData() })
How can I apply the original HTML styling to the content I generate dynamically with JavaScript?
Hey there! The issue right now is that your JavaScript is only adding a barebones card container with just the title and body—you need to replicate the full card structure from your original Django template in your JS template string. Here's how to do it step by step:
1. First, make sure your backend JSON response includes all required fields
Before updating the JS, confirm your /posts-json/${visible}/ endpoint returns every piece of data you need for the card:
slug(for the detail/edit/delete URLs)blog_cover_image_url(ornullif there's no image)titletruncated_body(pre-processed to remove tags and slice to 250 characters—better to do this on the backend than frontend)created_at(raw ISO date or pre-formatted string)author_first_name,author_last_nameis_editable(a boolean indicating if the current user can edit/delete the post—avoids complex auth logic in JS)edit_urlanddelete_url(or you can construct these frontend-side if you have the slug)
2. Replace your JS card template with the full structure
Update the data.map(post => { ... }) block in your handleGetData function to use the complete card HTML, replacing Django template variables with your post object properties:
data.map(post => { // Build cover image with conditional placeholder logic const coverImage = post.blog_cover_image_url ? `<img class="img-fluid rounded" style="max-height:1000px;max-width:1200px;" src="${post.blog_cover_image_url}" alt="Blog cover" />` : `<img class="img-fluid rounded" style="max-height:1000px;max-width:1200px;" src="https://via.placeholder.com/900x300" alt="Blog cover placeholder" />`; // Build edit/delete buttons only if user has permission const editDeleteButtons = post.is_editable ? `<a href="${post.edit_url}"><b>(Edit Blog)</b></a> <a href="${post.delete_url}"><b>(Delete Blog)</b></a>` : ''; // Format date to match your original template's style const formattedDate = new Date(post.created_at).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); // Assemble the full card HTML const cardHtml = ` <div class="card mb-4"> ${coverImage} <div class="card-body"> <h2 class="card-title"><a href="/blog/${post.slug}/">${post.title}</a></h2> <p class="card-text">${post.truncated_body}</p> <a class="btn btn-primary" href="/blog/${post.slug}/">Read More →</a> </div> <div class="card-footer text-muted"> Posted on (${formattedDate}) <div class="author">${post.author_first_name} ${post.author_last_name} ${editDeleteButtons}</div> </div> </div> `; postsBox.innerHTML += cardHtml; })
3. Key notes to keep in mind
- URL Construction: If you don't want to return
edit_url/delete_urlfrom the backend, you can build them using the slug (e.g.,/blog/edit/${post.slug}/)—just ensure they match your Django URL patterns. - Performance: For large numbers of posts,
innerHTML +=can get slow. Instead, build an array of card strings and dopostsBox.innerHTML += cards.join('')once at the end. - Security: Always validate edit/delete permissions on the backend, even if you hide the buttons frontend-side—never trust frontend-only auth checks.
- Date Formatting: Adjust the
toLocaleDateStringoptions to match the date style in your original template.
This will make your dynamically loaded posts look identical to the ones rendered by your Django template!
内容的提问来源于stack exchange,提问作者boyenec

