You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django实时搜索功能JQuery报错:无法访问blogpost['title']属性(值为空)

问题根源分析

你遇到的blogpost['title']为空/undefined的问题,核心原因是Django的serializers.serialize()返回的JSON结构和你前端预期的不一样。

默认的serializers.serialize("json", all_blogposts)会把每条博客数据包装成一个包含model、pk、fields三个键的对象,比如一条数据的结构是这样的:

{
  "model": "blog.blogpost",
  "pk": 1,
  "fields": {
    "title": "My First Post",
    "subtitle": "A test post",
    "slug": "my-first-post",
    "image": "/media/posts/image.jpg",
    "category": "Tech"
  }
}

而你前端代码里直接访问blogpost['title'],自然找不到这个键,所以会报错。


修复方案

我给你两种修复思路,选哪种都可以:

方案1:修改前端代码(最快,不需要动后端)

直接调整前端访问字段的路径,从blogpost['title']改成blogpost.fields.title,同时优化JSON的处理方式(Django模板可以直接用|safe过滤器避免手动转义):

修改后的JQuery代码

<script>
// 用|safe过滤器让Django直接输出正确的JSON,不用手动替换转义符
var data = '{{ qs_json|safe }}';
const rdata = JSON.parse(data);
const input = document.getElementById('search_form');
const jsbox = document.getElementById('jsbox'); // 补充声明jsbox元素,避免未定义报错

input.addEventListener('keyup', (e) => {
  jsbox.innerHTML = "";
  const searchTerm = e.target.value.trim().toLowerCase();
  // 调整字段访问路径到fields下
  const filteredArr = rdata.filter(blogpost => 
    blogpost.fields.title.toLowerCase().includes(searchTerm)
  );

  if (filteredArr.length > 0) {
    filteredArr.forEach(blogpost => { // 用forEach比map更合适,不需要返回值
      jsbox.innerHTML += `
        <div class="col mt-5 ml-1">
          <a href="blog/${blogpost.fields.slug}" style="text-decoration: none">
            <div class="card">
              <div class='blogpost_image_container'>
                <img src="${blogpost.fields.image}" class="card-img-top" alt="blogpost image">
              </div>
              <div class="card-body">
                <h5 class="card-title">${blogpost.fields.title} </h5>
                <p class="card-text"> ${blogpost.fields.subtitle} </p>
                <span id="category_badge" class="badge rounded-pill bg-warning text-dark"> ${blogpost.fields.category} </span>
              </div>
            </div>
          </a>
        </div>
      `;
    });
  } else {
    jsbox.innerHTML = `<div class="col mt-5 ml-1">
      <h5 class="card-title"> No Matches Found! </h5>
    </div>`;
  }
});
</script>

方案2:修改后端代码(让JSON结构更扁平,前端不用改)

如果不想调整前端,可以让后端返回直接包含字段的JSON,用values()方法代替serializers.serialize():

修改后的Django视图代码

import json
from django.views.generic import ListView
from .models import BlogPost, Category

class BlogListView(ListView):
    model = BlogPost
    template_name = "blog/blog.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.request.GET.get('category_filter'):
            cat_filter = self.request.GET.get('category_filter')
            all_blogposts = BlogPost.objects.filter(category=cat_filter)
        else:
            all_blogposts = BlogPost.objects.all()
        
        # 用values()获取扁平的字段键值对,转成JSON
        data = json.dumps(list(all_blogposts.values('title', 'subtitle', 'slug', 'image', 'category')))
        context["qs_json"] = data
        context["blogposts"] = all_blogposts
        context["categories"] = Category.objects.all()
        return context

这样后端返回的JSON结构就是你前端预期的:

[
  {
    "title": "My First Post",
    "subtitle": "A test post",
    "slug": "my-first-post",
    "image": "/media/posts/image.jpg",
    "category": "Tech"
  }
]

这种方式下,你原有的前端代码只需要补充jsbox变量声明,就能直接用blogpost['title']访问字段。


额外提示
  • 用values()时建议明确指定需要的字段,避免返回不必要的数据;
  • 如果你的项目使用了Django REST Framework,可以用它的序列化器更灵活地控制JSON结构;
  • 前端处理搜索词时,加上trim()可以避免空字符的无意义匹配。

内容的提问来源于stack exchange,提问作者Zer0Designs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:34:05