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

如何将Scrapy爬取数据存入Django PostgreSQL的两张关联表并配置Sqlalchemy关系

解决方案

1 调整SQLAlchemy侧models.py关联配置

补全导入,添加外键和关联关系,修改后代码如下:

# models.py - Sqlalchemy
from sqlalchemy import Column, Integer, String, create_engine, Boolean, DateTime, ForeignKey, Table, event
from sqlalchemy.orm import relationship, declarative_base # 新增导入relationship
from . import settings

DeclarativeBase = declarative_base()

class Shop_Product(DeclarativeBase):
    __tablename__ = "shop_product"
    id = Column(Integer, primary_key=True)
    slug = Column("slug", String, unique=True)
    title = Column("title", String)
    # 新增反向关联,和Django侧related_name保持一致,cascade设置为删除商品时同步删除关联图片
    product_image = relationship("Shop_ProductImage", back_populates="product", cascade="all, delete-orphan")
    
class Shop_ProductImage(DeclarativeBase):
    __tablename__ = "shop_productimage"
    id = Column(Integer, primary_key=True)
    # 修改product_id为外键,关联商品表id
    product_id = Column("product_id", Integer, ForeignKey("shop_product.id"), nullable=False)
    image = Column("image", String)
    # 新增正向关联,指向商品实例
    product = relationship("Shop_Product", back_populates="product_image")

修改说明:

  • 给product_id字段添加ForeignKey约束,和Django侧的外键逻辑对齐,保证数据一致性
  • 添加双向relationship关联,后续可以直接通过商品实例操作关联的图片数据,不需要手动查询关联id
  • cascade配置和Django侧on_delete=models.CASCADE逻辑一致,删除商品时自动删除关联的图片数据

2 修改Scrapy侧Pipeline实现双表同步写入

调整process_item方法,在商品数据写入完成后,同步写入图片数据,修改后代码如下:

# piplines.py
from sqlalchemy.orm import sessionmaker
from .models import Shop_Product, Shop_ProductImage, create_items_table, db_connect # 新增导入Shop_ProductImage

class ShoppSpinderPipeline(object):
    def __init__(self):       
        engine = db_connect()
        create_items_table(engine)
        Session = sessionmaker(bind=engine)
        self.session = Session()

    def process_item(self, item, spider):
        item_exists = self.session.query(Shop_Product).filter_by(slug=item['slug']).first()

        if item_exists:
            item_exists.title = item['title']
            print('SP {} updated.'.format(item['title']))
            product_instance = item_exists
        else:
            new_item = Shop_Product(title=item['title'], slug=item['slug']) # 不要直接传**item,避免把image字段传给商品模型
            self.session.add(new_item)
            self.session.flush() # flush后可以拿到新增商品的自增id,不需要先commit
            product_instance = new_item
            print('Item {} created.'.format(item['title']))
        
        # 处理图片数据写入
        if item.get('image'):
            # 单图逻辑:查询该商品是否已有图片,有则更新,无则新增;多图可调整为循环写入
            image_exists = self.session.query(Shop_ProductImage).filter_by(product_id=product_instance.id).first()
            if image_exists:
                image_exists.image = item['image']
            else:
                new_image = Shop_ProductImage(product_id=product_instance.id, image=item['image'])
                self.session.add(new_image)
        return item

    def close_spider(self, spider):
        try:
            self.session.commit()
        except:
            self.session.rollback()
            raise
        finally:
            self.session.close()

修改说明:

  • 新增商品时不要直接用**item实例化商品模型,避免把image字段传入商品表导致报错
  • 新增商品后调用session.flush()即可拿到自增id,不需要提前提交事务,保证数据一致性
  • 图片写入逻辑支持单图更新/新增,若业务为多图,可将item的image字段改为列表,循环创建Shop_ProductImage实例即可

注意:如果需要Scrapy自动下载图片,需先开启Scrapy自带的ImagesPipeline,将下载后的本地存储路径赋值给item的image字段,路径需要和Django侧upload_to="product_images/"的配置匹配,保证Django可以正常读取图片。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:36:02