We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CSV export does not include read date
**Describe the bug**
When exporting data into a CSV file, several fields are exported, but `read date` is not one of them, despite being exremelly valuable.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to 'Profile'
2. Click on 'Export to CSV'
3. Download CSV file
4. Open CSV file

**Expected behavior**
A column containing read date should be included among the current ones

**Instance**
bookwyrm.social



---

**Desktop (please complete the following information):**
    - OS: KDE Neon
    - Browser Firefox, Chromium
    - Version 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bookwyrm/views/preferences/export.py`
Content:
```
1 """ Let users export their book data """
2 from datetime import timedelta
3 import csv
4 import io
5 
6 from django.contrib.auth.decorators import login_required
7 from django.core.paginator import Paginator
8 from django.db.models import Q
9 from django.http import HttpResponse
10 from django.template.response import TemplateResponse
11 from django.utils import timezone
12 from django.views import View
13 from django.utils.decorators import method_decorator
14 from django.shortcuts import redirect
15 
16 from bookwyrm import models
17 from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob
18 from bookwyrm.settings import PAGE_LENGTH
19 
20 # pylint: disable=no-self-use
21 @method_decorator(login_required, name="dispatch")
22 class Export(View):
23     """Let users export data"""
24 
25     def get(self, request):
26         """Request csv file"""
27         return TemplateResponse(request, "preferences/export.html")
28 
29     def post(self, request):
30         """Download the csv file of a user's book data"""
31         books = models.Edition.viewer_aware_objects(request.user)
32         books_shelves = books.filter(Q(shelves__user=request.user)).distinct()
33         books_readthrough = books.filter(Q(readthrough__user=request.user)).distinct()
34         books_review = books.filter(Q(review__user=request.user)).distinct()
35         books_comment = books.filter(Q(comment__user=request.user)).distinct()
36         books_quotation = books.filter(Q(quotation__user=request.user)).distinct()
37 
38         books = set(
39             list(books_shelves)
40             + list(books_readthrough)
41             + list(books_review)
42             + list(books_comment)
43             + list(books_quotation)
44         )
45 
46         csv_string = io.StringIO()
47         writer = csv.writer(csv_string)
48 
49         deduplication_fields = [
50             f.name
51             for f in models.Edition._meta.get_fields()  # pylint: disable=protected-access
52             if getattr(f, "deduplication_field", False)
53         ]
54         fields = (
55             ["title", "author_text"]
56             + deduplication_fields
57             + ["rating", "review_name", "review_cw", "review_content"]
58         )
59         writer.writerow(fields)
60 
61         for book in books:
62             # I think this is more efficient than doing a subquery in the view? but idk
63             review_rating = (
64                 models.Review.objects.filter(
65                     user=request.user, book=book, rating__isnull=False
66                 )
67                 .order_by("-published_date")
68                 .first()
69             )
70 
71             book.rating = review_rating.rating if review_rating else None
72 
73             review = (
74                 models.Review.objects.filter(
75                     user=request.user, book=book, content__isnull=False
76                 )
77                 .order_by("-published_date")
78                 .first()
79             )
80             if review:
81                 book.review_name = review.name
82                 book.review_cw = review.content_warning
83                 book.review_content = review.raw_content
84             writer.writerow([getattr(book, field, "") or "" for field in fields])
85 
86         return HttpResponse(
87             csv_string.getvalue(),
88             content_type="text/csv",
89             headers={
90                 "Content-Disposition": 'attachment; filename="bookwyrm-export.csv"'
91             },
92         )
93 
94 
95 # pylint: disable=no-self-use
96 @method_decorator(login_required, name="dispatch")
97 class ExportUser(View):
98     """Let users export user data to import into another Bookwyrm instance"""
99 
100     def get(self, request):
101         """Request tar file"""
102 
103         jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by(
104             "-created_date"
105         )
106         site = models.SiteSettings.objects.get()
107         hours = site.user_import_time_limit
108         allowed = (
109             jobs.first().created_date < timezone.now() - timedelta(hours=hours)
110             if jobs.first()
111             else True
112         )
113         next_available = (
114             jobs.first().created_date + timedelta(hours=hours) if not allowed else False
115         )
116         paginated = Paginator(jobs, PAGE_LENGTH)
117         page = paginated.get_page(request.GET.get("page"))
118         data = {
119             "jobs": page,
120             "next_available": next_available,
121             "page_range": paginated.get_elided_page_range(
122                 page.number, on_each_side=2, on_ends=1
123             ),
124         }
125 
126         return TemplateResponse(request, "preferences/export-user.html", data)
127 
128     def post(self, request):
129         """Download the json file of a user's data"""
130 
131         job = BookwyrmExportJob.objects.create(user=request.user)
132         job.start_job()
133 
134         return redirect("prefs-user-export")
135 
136 
137 @method_decorator(login_required, name="dispatch")
138 class ExportArchive(View):
139     """Serve the archive file"""
140 
141     def get(self, request, archive_id):
142         """download user export file"""
143         export = BookwyrmExportJob.objects.get(task_id=archive_id, user=request.user)
144         return HttpResponse(
145             export.export_data,
146             content_type="application/gzip",
147             headers={
148                 "Content-Disposition": 'attachment; filename="bookwyrm-account-export.tar.gz"'  # pylint: disable=line-too-long
149             },
150         )
151
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py
--- a/bookwyrm/views/preferences/export.py
+++ b/bookwyrm/views/preferences/export.py
@@ -17,7 +17,7 @@
 from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob
 from bookwyrm.settings import PAGE_LENGTH
 
-# pylint: disable=no-self-use
+# pylint: disable=no-self-use,too-many-locals
 @method_decorator(login_required, name="dispatch")
 class Export(View):
     """Let users export data"""
@@ -54,6 +54,7 @@
         fields = (
             ["title", "author_text"]
             + deduplication_fields
+            + ["start_date", "finish_date", "stopped_date"]
             + ["rating", "review_name", "review_cw", "review_content"]
         )
         writer.writerow(fields)
@@ -70,6 +71,24 @@
 
             book.rating = review_rating.rating if review_rating else None
 
+            readthrough = (
+                models.ReadThrough.objects.filter(user=request.user, book=book)
+                .order_by("-start_date", "-finish_date")
+                .first()
+            )
+            if readthrough:
+                book.start_date = (
+                    readthrough.start_date.date() if readthrough.start_date else None
+                )
+                book.finish_date = (
+                    readthrough.finish_date.date() if readthrough.finish_date else None
+                )
+                book.stopped_date = (
+                    readthrough.stopped_date.date()
+                    if readthrough.stopped_date
+                    else None
+                )
+
             review = (
                 models.Review.objects.filter(
                     user=request.user, book=book, content__isnull=False

{"golden_diff": "diff --git a/bookwyrm/views/preferences/export.py b/bookwyrm/views/preferences/export.py\n--- a/bookwyrm/views/preferences/export.py\n+++ b/bookwyrm/views/preferences/export.py\n@@ -17,7 +17,7 @@\n from bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob\n from bookwyrm.settings import PAGE_LENGTH\n \n-# pylint: disable=no-self-use\n+# pylint: disable=no-self-use,too-many-locals\n @method_decorator(login_required, name=\"dispatch\")\n class Export(View):\n     \"\"\"Let users export data\"\"\"\n@@ -54,6 +54,7 @@\n         fields = (\n             [\"title\", \"author_text\"]\n             + deduplication_fields\n+            + [\"start_date\", \"finish_date\", \"stopped_date\"]\n             + [\"rating\", \"review_name\", \"review_cw\", \"review_content\"]\n         )\n         writer.writerow(fields)\n@@ -70,6 +71,24 @@\n \n             book.rating = review_rating.rating if review_rating else None\n \n+            readthrough = (\n+                models.ReadThrough.objects.filter(user=request.user, book=book)\n+                .order_by(\"-start_date\", \"-finish_date\")\n+                .first()\n+            )\n+            if readthrough:\n+                book.start_date = (\n+                    readthrough.start_date.date() if readthrough.start_date else None\n+                )\n+                book.finish_date = (\n+                    readthrough.finish_date.date() if readthrough.finish_date else None\n+                )\n+                book.stopped_date = (\n+                    readthrough.stopped_date.date()\n+                    if readthrough.stopped_date\n+                    else None\n+                )\n+\n             review = (\n                 models.Review.objects.filter(\n                     user=request.user, book=book, content__isnull=False\n", "issue": "CSV export does not include read date\n**Describe the bug**\r\nWhen exporting data into a CSV file, several fields are exported, but `read date` is not one of them, despite being exremelly valuable.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Go to 'Profile'\r\n2. Click on 'Export to CSV'\r\n3. Download CSV file\r\n4. Open CSV file\r\n\r\n**Expected behavior**\r\nA column containing read date should be included among the current ones\r\n\r\n**Instance**\r\nbookwyrm.social\r\n\r\n\r\n\r\n---\r\n\r\n**Desktop (please complete the following information):**\r\n    - OS: KDE Neon\r\n    - Browser Firefox, Chromium\r\n    - Version \r\n\n", "before_files": [{"content": "\"\"\" Let users export their book data \"\"\"\nfrom datetime import timedelta\nimport csv\nimport io\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.paginator import Paginator\nfrom django.db.models import Q\nfrom django.http import HttpResponse\nfrom django.template.response import TemplateResponse\nfrom django.utils import timezone\nfrom django.views import View\nfrom django.utils.decorators import method_decorator\nfrom django.shortcuts import redirect\n\nfrom bookwyrm import models\nfrom bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob\nfrom bookwyrm.settings import PAGE_LENGTH\n\n# pylint: disable=no-self-use\n@method_decorator(login_required, name=\"dispatch\")\nclass Export(View):\n    \"\"\"Let users export data\"\"\"\n\n    def get(self, request):\n        \"\"\"Request csv file\"\"\"\n        return TemplateResponse(request, \"preferences/export.html\")\n\n    def post(self, request):\n        \"\"\"Download the csv file of a user's book data\"\"\"\n        books = models.Edition.viewer_aware_objects(request.user)\n        books_shelves = books.filter(Q(shelves__user=request.user)).distinct()\n        books_readthrough = books.filter(Q(readthrough__user=request.user)).distinct()\n        books_review = books.filter(Q(review__user=request.user)).distinct()\n        books_comment = books.filter(Q(comment__user=request.user)).distinct()\n        books_quotation = books.filter(Q(quotation__user=request.user)).distinct()\n\n        books = set(\n            list(books_shelves)\n            + list(books_readthrough)\n            + list(books_review)\n            + list(books_comment)\n            + list(books_quotation)\n        )\n\n        csv_string = io.StringIO()\n        writer = csv.writer(csv_string)\n\n        deduplication_fields = [\n            f.name\n            for f in models.Edition._meta.get_fields()  # pylint: disable=protected-access\n            if getattr(f, \"deduplication_field\", False)\n        ]\n        fields = (\n            [\"title\", \"author_text\"]\n            + deduplication_fields\n            + [\"rating\", \"review_name\", \"review_cw\", \"review_content\"]\n        )\n        writer.writerow(fields)\n\n        for book in books:\n            # I think this is more efficient than doing a subquery in the view? but idk\n            review_rating = (\n                models.Review.objects.filter(\n                    user=request.user, book=book, rating__isnull=False\n                )\n                .order_by(\"-published_date\")\n                .first()\n            )\n\n            book.rating = review_rating.rating if review_rating else None\n\n            review = (\n                models.Review.objects.filter(\n                    user=request.user, book=book, content__isnull=False\n                )\n                .order_by(\"-published_date\")\n                .first()\n            )\n            if review:\n                book.review_name = review.name\n                book.review_cw = review.content_warning\n                book.review_content = review.raw_content\n            writer.writerow([getattr(book, field, \"\") or \"\" for field in fields])\n\n        return HttpResponse(\n            csv_string.getvalue(),\n            content_type=\"text/csv\",\n            headers={\n                \"Content-Disposition\": 'attachment; filename=\"bookwyrm-export.csv\"'\n            },\n        )\n\n\n# pylint: disable=no-self-use\n@method_decorator(login_required, name=\"dispatch\")\nclass ExportUser(View):\n    \"\"\"Let users export user data to import into another Bookwyrm instance\"\"\"\n\n    def get(self, request):\n        \"\"\"Request tar file\"\"\"\n\n        jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by(\n            \"-created_date\"\n        )\n        site = models.SiteSettings.objects.get()\n        hours = site.user_import_time_limit\n        allowed = (\n            jobs.first().created_date < timezone.now() - timedelta(hours=hours)\n            if jobs.first()\n            else True\n        )\n        next_available = (\n            jobs.first().created_date + timedelta(hours=hours) if not allowed else False\n        )\n        paginated = Paginator(jobs, PAGE_LENGTH)\n        page = paginated.get_page(request.GET.get(\"page\"))\n        data = {\n            \"jobs\": page,\n            \"next_available\": next_available,\n            \"page_range\": paginated.get_elided_page_range(\n                page.number, on_each_side=2, on_ends=1\n            ),\n        }\n\n        return TemplateResponse(request, \"preferences/export-user.html\", data)\n\n    def post(self, request):\n        \"\"\"Download the json file of a user's data\"\"\"\n\n        job = BookwyrmExportJob.objects.create(user=request.user)\n        job.start_job()\n\n        return redirect(\"prefs-user-export\")\n\n\n@method_decorator(login_required, name=\"dispatch\")\nclass ExportArchive(View):\n    \"\"\"Serve the archive file\"\"\"\n\n    def get(self, request, archive_id):\n        \"\"\"download user export file\"\"\"\n        export = BookwyrmExportJob.objects.get(task_id=archive_id, user=request.user)\n        return HttpResponse(\n            export.export_data,\n            content_type=\"application/gzip\",\n            headers={\n                \"Content-Disposition\": 'attachment; filename=\"bookwyrm-account-export.tar.gz\"'  # pylint: disable=line-too-long\n            },\n        )\n", "path": "bookwyrm/views/preferences/export.py"}], "after_files": [{"content": "\"\"\" Let users export their book data \"\"\"\nfrom datetime import timedelta\nimport csv\nimport io\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.paginator import Paginator\nfrom django.db.models import Q\nfrom django.http import HttpResponse\nfrom django.template.response import TemplateResponse\nfrom django.utils import timezone\nfrom django.views import View\nfrom django.utils.decorators import method_decorator\nfrom django.shortcuts import redirect\n\nfrom bookwyrm import models\nfrom bookwyrm.models.bookwyrm_export_job import BookwyrmExportJob\nfrom bookwyrm.settings import PAGE_LENGTH\n\n# pylint: disable=no-self-use,too-many-locals\n@method_decorator(login_required, name=\"dispatch\")\nclass Export(View):\n    \"\"\"Let users export data\"\"\"\n\n    def get(self, request):\n        \"\"\"Request csv file\"\"\"\n        return TemplateResponse(request, \"preferences/export.html\")\n\n    def post(self, request):\n        \"\"\"Download the csv file of a user's book data\"\"\"\n        books = models.Edition.viewer_aware_objects(request.user)\n        books_shelves = books.filter(Q(shelves__user=request.user)).distinct()\n        books_readthrough = books.filter(Q(readthrough__user=request.user)).distinct()\n        books_review = books.filter(Q(review__user=request.user)).distinct()\n        books_comment = books.filter(Q(comment__user=request.user)).distinct()\n        books_quotation = books.filter(Q(quotation__user=request.user)).distinct()\n\n        books = set(\n            list(books_shelves)\n            + list(books_readthrough)\n            + list(books_review)\n            + list(books_comment)\n            + list(books_quotation)\n        )\n\n        csv_string = io.StringIO()\n        writer = csv.writer(csv_string)\n\n        deduplication_fields = [\n            f.name\n            for f in models.Edition._meta.get_fields()  # pylint: disable=protected-access\n            if getattr(f, \"deduplication_field\", False)\n        ]\n        fields = (\n            [\"title\", \"author_text\"]\n            + deduplication_fields\n            + [\"start_date\", \"finish_date\", \"stopped_date\"]\n            + [\"rating\", \"review_name\", \"review_cw\", \"review_content\"]\n        )\n        writer.writerow(fields)\n\n        for book in books:\n            # I think this is more efficient than doing a subquery in the view? but idk\n            review_rating = (\n                models.Review.objects.filter(\n                    user=request.user, book=book, rating__isnull=False\n                )\n                .order_by(\"-published_date\")\n                .first()\n            )\n\n            book.rating = review_rating.rating if review_rating else None\n\n            readthrough = (\n                models.ReadThrough.objects.filter(user=request.user, book=book)\n                .order_by(\"-start_date\", \"-finish_date\")\n                .first()\n            )\n            if readthrough:\n                book.start_date = (\n                    readthrough.start_date.date() if readthrough.start_date else None\n                )\n                book.finish_date = (\n                    readthrough.finish_date.date() if readthrough.finish_date else None\n                )\n                book.stopped_date = (\n                    readthrough.stopped_date.date()\n                    if readthrough.stopped_date\n                    else None\n                )\n\n            review = (\n                models.Review.objects.filter(\n                    user=request.user, book=book, content__isnull=False\n                )\n                .order_by(\"-published_date\")\n                .first()\n            )\n            if review:\n                book.review_name = review.name\n                book.review_cw = review.content_warning\n                book.review_content = review.raw_content\n            writer.writerow([getattr(book, field, \"\") or \"\" for field in fields])\n\n        return HttpResponse(\n            csv_string.getvalue(),\n            content_type=\"text/csv\",\n            headers={\n                \"Content-Disposition\": 'attachment; filename=\"bookwyrm-export.csv\"'\n            },\n        )\n\n\n# pylint: disable=no-self-use\n@method_decorator(login_required, name=\"dispatch\")\nclass ExportUser(View):\n    \"\"\"Let users export user data to import into another Bookwyrm instance\"\"\"\n\n    def get(self, request):\n        \"\"\"Request tar file\"\"\"\n\n        jobs = BookwyrmExportJob.objects.filter(user=request.user).order_by(\n            \"-created_date\"\n        )\n        site = models.SiteSettings.objects.get()\n        hours = site.user_import_time_limit\n        allowed = (\n            jobs.first().created_date < timezone.now() - timedelta(hours=hours)\n            if jobs.first()\n            else True\n        )\n        next_available = (\n            jobs.first().created_date + timedelta(hours=hours) if not allowed else False\n        )\n        paginated = Paginator(jobs, PAGE_LENGTH)\n        page = paginated.get_page(request.GET.get(\"page\"))\n        data = {\n            \"jobs\": page,\n            \"next_available\": next_available,\n            \"page_range\": paginated.get_elided_page_range(\n                page.number, on_each_side=2, on_ends=1\n            ),\n        }\n\n        return TemplateResponse(request, \"preferences/export-user.html\", data)\n\n    def post(self, request):\n        \"\"\"Download the json file of a user's data\"\"\"\n\n        job = BookwyrmExportJob.objects.create(user=request.user)\n        job.start_job()\n\n        return redirect(\"prefs-user-export\")\n\n\n@method_decorator(login_required, name=\"dispatch\")\nclass ExportArchive(View):\n    \"\"\"Serve the archive file\"\"\"\n\n    def get(self, request, archive_id):\n        \"\"\"download user export file\"\"\"\n        export = BookwyrmExportJob.objects.get(task_id=archive_id, user=request.user)\n        return HttpResponse(\n            export.export_data,\n            content_type=\"application/gzip\",\n            headers={\n                \"Content-Disposition\": 'attachment; filename=\"bookwyrm-account-export.tar.gz\"'  # pylint: disable=line-too-long\n            },\n        )\n", "path": "bookwyrm/views/preferences/export.py"}]}