Files
green_classroom/WEBSITES_FIELD_FIX.md
2025-09-24 04:02:43 +08:00

5.0 KiB
Raw Blame History

网站字段修复说明

问题描述

您遇到了 "can only join an iterable" 错误,这是因为将 CrawlTask 模型中的 websites 字段从 JSONField 改为了 ManyToManyField,但代码中还有一些地方没有相应更新。

已修复的问题

1. 任务执行器修复

core/task_executor.py 中,已经修复了以下方法:

  • _execute_keyword_task() - 关键词搜索任务执行
  • _execute_historical_task() - 历史文章任务执行
  • _execute_full_site_task() - 全站爬取任务执行

修复前:

websites = task.websites if task.websites else list(WEBSITE_SEARCH_CONFIGS.keys())

修复后:

selected_websites = task.websites.all()
if selected_websites:
    websites = [w.name for w in selected_websites]
else:
    websites = list(WEBSITE_SEARCH_CONFIGS.keys())

2. 模型方法修复

core/models.py 中,get_websites_display() 方法已经正确处理了 ManyToManyField

def get_websites_display(self):
    """获取网站列表的显示文本"""
    try:
        websites = self.websites.all()
        if not websites:
            return "所有网站"
        # 确保网站名称是字符串并可以被join处理
        website_names = [str(w.name) for w in websites if w.name]
        return ", ".join(website_names) if website_names else "所有网站"
    except Exception:
        # 如果出现任何异常,返回默认值
        return "所有网站"

3. 管理界面修复

core/admin_extended.py 中,已经修复了任务创建逻辑:

  • 使用 Website.objects.filter(name__in=websites) 获取网站对象
  • 使用 task.websites.set(website_objects) 设置关联关系

测试验证

已经通过以下测试验证修复:

  1. 网站字段功能测试 - 验证 ManyToManyField 的基本操作
  2. 任务执行器测试 - 验证任务执行器中的网站获取逻辑
  3. Web界面操作测试 - 验证完整的Web界面操作流程
  4. 系统检查 - Django系统检查无错误

使用方法

1. 确保数据库迁移已应用

python manage.py migrate

2. 创建网站数据

如果还没有网站数据,可以通过以下方式创建:

from core.models import Website

# 创建一些测试网站
websites_to_create = ["新华网", "人民日报", "央视网"]
for name in websites_to_create:
    website, created = Website.objects.get_or_create(
        name=name,
        defaults={
            'base_url': f'http://{name}.com',
            'enabled': True
        }
    )

3. 通过Web界面创建任务

  1. 启动服务器:python manage.py runserver
  2. 访问管理后台:http://localhost:8000/admin/
  3. 在首页点击"快速创建爬取任务"
  4. 选择任务类型并填写相关信息
  5. 选择目标网站
  6. 创建并启动任务

4. 通过命令行创建任务

# 关键词搜索
python manage.py crawl_by_keyword --keyword "人工智能"

# 历史文章爬取
python manage.py crawl_by_keyword --keyword "新闻" --historical

# 多网站一键爬取
python manage.py crawl_all_websites --mode both --keyword "人工智能"

故障排除

如果仍然遇到 "can only join an iterable" 错误

  1. 检查数据库迁移

    python manage.py showmigrations core
    python manage.py migrate
    
  2. 检查网站数据

    from core.models import Website
    print(Website.objects.filter(enabled=True).count())
    
  3. 检查任务数据

    from core.models import CrawlTask
    task = CrawlTask.objects.first()
    if task:
        print(f"任务网站: {task.get_websites_display()}")
    
  4. 重启服务器

    # 停止当前服务器 (Ctrl+C)
    python manage.py runserver
    

如果遇到其他错误

  1. 检查日志查看Django日志输出
  2. 检查网络连接:确保可以访问目标网站
  3. 检查网站配置:确保 WEBSITE_SEARCH_CONFIGS 中的配置正确

技术细节

ManyToManyField vs JSONField

之前的JSONField方式

websites = models.JSONField(default=list, verbose_name="目标网站")
# 使用: task.websites = ["新华网", "人民日报"]

现在的ManyToManyField方式

websites = models.ManyToManyField(Website, blank=True, verbose_name="目标网站")
# 使用: task.websites.set(website_objects)

优势

  1. 数据完整性:通过外键关系确保数据一致性
  2. 查询效率:可以利用数据库索引进行高效查询
  3. 关系管理Django自动处理多对多关系的创建和删除
  4. 数据验证:自动验证关联的网站是否存在

总结

修复已经完成,现在您可以:

  1. 通过Web界面创建和管理爬取任务
  2. 选择特定的网站进行爬取
  3. 实时监控任务进度
  4. 查看详细的爬取结果

如果仍然遇到问题,请检查:

  • 数据库迁移是否已应用
  • 网站数据是否存在
  • 服务器是否已重启

系统现在应该可以正常工作了!