diff --git a/chainerui/models/__init__.py b/chainerui/models/__init__.py
index d0dc9f0..77c7c1e 100644
--- a/chainerui/models/__init__.py
+++ b/chainerui/models/__init__.py
@@ -1,4 +1,6 @@
 from chainerui.models.argument import Argument  # NOQA
+from chainerui.models.asset import Asset  # NOQA
+from chainerui.models.bindata import Bindata  # NOQA
 from chainerui.models.command import Command  # NOQA
 from chainerui.models.log import Log  # NOQA
 from chainerui.models.project import Project  # NOQA
diff --git a/chainerui/models/result.py b/chainerui/models/result.py
index 0050e7d..ea8932d 100644
--- a/chainerui/models/result.py
+++ b/chainerui/models/result.py
@@ -28,6 +28,7 @@ class Result(database.BASE):
     )
     commands = relationship('Command', cascade='all, delete-orphan')
     snapshots = relationship('Snapshot', cascade='all, delete-orphan')
+    assets = relationship('Asset', cascade='all, delete-orphan')
     log_modified_at = Column(DateTime, default=None)
     created_at = Column(DateTime, default=datetime.datetime.now())
     updated_at = Column(
diff --git a/chainerui/tasks/collect_assets.py b/chainerui/tasks/collect_assets.py
index f74b2af..87b4a77 100644
--- a/chainerui/tasks/collect_assets.py
+++ b/chainerui/tasks/collect_assets.py
@@ -9,7 +9,7 @@ from chainerui.models.bindata import Bindata
 from chainerui import summary
 
 
-def collect_assets(result, assets, force=False):
+def collect_assets(result, force=False):
     """collect assets from meta file
 
     Collecting assets only when the metafile is updated. If number of assets
@@ -17,21 +17,21 @@ def collect_assets(result, assets, force=False):
     """
     path_name = result.path_name
     info_path = os.path.join(path_name, summary.CHAINERUI_ASSETS_METAFILE_NAME)
-    start_idx = len(assets)
     if not os.path.isfile(info_path):
-        return assets
+        return
+    start_idx = len(result.assets)
     file_modified_at = datetime.datetime.fromtimestamp(os.path.getmtime(
         info_path))
     if start_idx > 0:
-        if assets[-1].file_modified_at == file_modified_at:
-            return assets
+        if result.assets[-1].file_modified_at == file_modified_at:
+            return
 
     with open(info_path, 'r') as f:
         info_list = json.load(f, object_pairs_hook=OrderedDict)
 
     if len(info_list) < start_idx:
         start_idx = 0
-        assets = []
+        result.assets = []
 
     for base_info in info_list[start_idx:]:
         asset_path = base_info.pop('images', {})
@@ -45,8 +45,6 @@ def collect_assets(result, assets, force=False):
             content = Bindata(
                 asset_id=asset.id, name=path, tag=key, content=data)
             asset.content_list.append(content)
-        assets.append(asset)
+        result.assets.append(asset)
 
     db.session.commit()
-
-    return assets
diff --git a/chainerui/views/result_asset.py b/chainerui/views/result_asset.py
index c4bd790..d7b63cc 100644
--- a/chainerui/views/result_asset.py
+++ b/chainerui/views/result_asset.py
@@ -5,7 +5,6 @@ from flask import send_file
 from flask.views import MethodView
 
 from chainerui.database import db
-from chainerui.models.asset import Asset
 from chainerui.models.bindata import Bindata
 from chainerui.models.project import Project
 from chainerui.models.result import Result
@@ -37,13 +36,8 @@ class ResultAssetAPI(MethodView):
             }), 404
 
         if content_id is None:
-            assets = db.session.query(Asset).\
-                filter_by(result_id=result_id).\
-                order_by(Asset.id).all()
-            if assets is None:
-                assets = []
-            assets = collect_assets(result, assets)
-            assets_response = [asset.serialize for asset in assets]
+            collect_assets(result)
+            assets_response = [asset.serialize for asset in result.assets]
             for asset in assets_response:
                 for content in asset['contents']:
                     content['uri'] = self._make_content_uri(

Assets are not deleted
Even if a project is deleted, asset related with the project is remain on database. When register new project, results show remained assets, not new one.

I'll send a PR from https://github.com/disktnk/chainerui/tree/fix/asset-delete to fix it, after merge #214 , 
diff --git a/tests/tasks_tests/test_collect_assets.py b/tests/tasks_tests/test_collect_assets.py
index cf05c8f..182bcb9 100644
--- a/tests/tasks_tests/test_collect_assets.py
+++ b/tests/tasks_tests/test_collect_assets.py
@@ -57,13 +57,14 @@ def test_collect_assets_no_meta(func_dir):
     os.remove(os.path.join(func_dir, summary.CHAINERUI_ASSETS_METAFILE_NAME))
     result = _get_dummy_result(func_dir)
 
-    actual_list = collect_assets.collect_assets(result, [])
-    assert len(actual_list) == 0
+    collect_assets.collect_assets(result)
+    assert len(result.assets) == 0
 
 
 def test_collect_assets(func_dir):
     result = _get_dummy_result(func_dir)
-    actual_list = collect_assets.collect_assets(result, [])
+    collect_assets.collect_assets(result)
+    actual_list = result.assets
 
     assert len(actual_list) == 2
     actual_img1 = actual_list[0]
@@ -96,17 +97,19 @@ def test_collect_assets(func_dir):
 
 def test_collect_assets_no_updated(func_dir):
     result = _get_dummy_result(func_dir)
-    first_assets = collect_assets.collect_assets(result, [])
+    collect_assets.collect_assets(result)
+    first_assets = result.assets
     assert len(first_assets) == 2
 
-    second_assets = collect_assets.collect_assets(result, first_assets)
-    assert first_assets == second_assets
+    collect_assets.collect_assets(result, first_assets)
+    assert first_assets == result.assets
 
 
 def test_collect_assets_updated(func_dir):
     info_path = os.path.join(func_dir, summary.CHAINERUI_ASSETS_METAFILE_NAME)
     result = _get_dummy_result(func_dir)
-    first_assets = collect_assets.collect_assets(result, [])
+    collect_assets.collect_assets(result)
+    first_assets = result.assets
     assert len(first_assets) == 2
 
     with open(os.path.join(func_dir, 'img1_3.png'), 'w') as f:
@@ -124,7 +127,8 @@ def test_collect_assets_updated(func_dir):
     with open(info_path, 'w') as f:
         json.dump(meta, f)
 
-    second_assets = collect_assets.collect_assets(result, first_assets)
+    collect_assets.collect_assets(result)
+    second_assets = result.assets
     assert len(second_assets) == 3
 
     actual_img3 = second_assets[2]
@@ -142,7 +146,8 @@ def test_collect_assets_updated(func_dir):
 def test_collect_assets_new_meta(func_dir):
     info_path = os.path.join(func_dir, summary.CHAINERUI_ASSETS_METAFILE_NAME)
     result = _get_dummy_result(func_dir)
-    first_assets = collect_assets.collect_assets(result, [])
+    collect_assets.collect_assets(result)
+    first_assets = result.assets
     assert len(first_assets) == 2
 
     test_data = [
@@ -157,7 +162,8 @@ def test_collect_assets_new_meta(func_dir):
     ]
     with open(info_path, 'w') as f:
         json.dump(test_data, f)
-    second_assets = collect_assets.collect_assets(result, first_assets)
+    collect_assets.collect_assets(result)
+    second_assets = result.assets
     assert len(second_assets) == 1
     actual_img1 = second_assets[0]
     assert len(actual_img1.content_list) == 2

pip install -e .
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y libsqlite3-dev
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alembic==1.7.7
attrs==22.2.0
certifi==2021.5.30
-e git+https://github.com/chainer/chainerui.git@01fb7b56582d90f15ab928d2860fded7ec80b31e#egg=chainerui
click==8.0.4
dataclasses==0.8
Flask==2.0.3
gevent==22.10.2
greenlet==2.0.2
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
itsdangerous==2.0.1
Jinja2==3.0.3
Mako==1.1.6
MarkupSafe==2.0.1
msgpack==1.0.5
packaging==21.3
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
SQLAlchemy==1.4.54
structlog==21.5.0
tomli==1.2.3
typing_extensions==4.1.1
Werkzeug==2.0.3
zipp==3.6.0
zope.event==4.6
zope.interface==5.5.2

name: chainerui
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alembic==1.7.7
      - attrs==22.2.0
      - click==8.0.4
      - dataclasses==0.8
      - flask==2.0.3
      - gevent==22.10.2
      - greenlet==2.0.2
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - itsdangerous==2.0.1
      - jinja2==3.0.3
      - mako==1.1.6
      - markupsafe==2.0.1
      - msgpack==1.0.5
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - sqlalchemy==1.4.54
      - structlog==21.5.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - werkzeug==2.0.3
      - zipp==3.6.0
      - zope-event==4.6
      - zope-interface==5.5.2
prefix: /opt/conda/envs/chainerui

tests/tasks_tests/test_collect_assets.py::test_collect_assets_no_meta tests/tasks_tests/test_collect_assets.py::test_collect_assets tests/tasks_tests/test_collect_assets.py::test_collect_assets_no_updated tests/tasks_tests/test_collect_assets.py::test_collect_assets_updated tests/tasks_tests/test_collect_assets.py::test_collect_assets_new_meta
chainerui/tasks/collect_assets.py chainerui/models/__init__.py chainerui/views/result_asset.py chainerui/models/result.py
chainerui/tasks/collect_assets.py chainerui/models/__init__.py chainerui/views/result_asset.py chainerui/models/result.py