Skip to content

Make series a separate model#3747

Open
hughrun wants to merge 28 commits intobookwyrm-social:mainfrom
hughrun:series-model
Open

Make series a separate model#3747
hughrun wants to merge 28 commits intobookwyrm-social:mainfrom
hughrun:series-model

Conversation

@hughrun
Copy link
Copy Markdown
Member

@hughrun hughrun commented Nov 20, 2025

Description

This PR moves book series to a pair of new models: Series and SeriesBook. This will allow more consistency around series, and for books to be matched to series regardless of whether they share an author. Basically it makes series "things, not strings".

A Series has basic BookData to better enable us to de-duplicate them, although only series imported from Inventaire are likely to have anything beyond a name. A SeriesBook connects a Series to a Book, including a series_number: it's the instantiation of a Book being part of a series.

When saving a book, users will be prompted to confirm whether it is part of an existing series, in the same way we check for existing authors.

All importers will now convert series information to a SeriesBook and Series where possible. If there is a matching series but no other book in the series with a matching author, the series information is left on the incoming book and users will be prompted to confirm the series information manually on the book view page.

Series can be edited, including updating the seriesnumber on one or more seriesbooks - users need to have permission to edit books to do this.

Creating a data migration proved to be challenging, so I have instead created an admin command to convert "legacy" series to Series and SeriesBooks where possible. This will need to be run by admins manually.

I have tried to make this backwards-compatible but it's entirely possibly that I've missed something.

I also added an atomic block to the user export model which is entirely unrelated except that I made a mistake when I was testing, and without this block I got a bunch of obscure errors.

This was a bit of a beast to put together so there may well be parts that could be more efficient or that I've missed - happy for any feedback!

What type of Pull Request is this?

  • Bug Fix
  • Enhancement
  • Plumbing / Internals / Dependencies
  • Refactor

Does this PR change settings or dependencies, or break something?

  • This PR changes or adds default settings, configuration, or .env values
  • This PR changes or adds dependencies
  • This PR introduces other breaking changes

Details of breaking or configuration changes (if any of above checked)

Documentation

  • New or amended documentation will be required if this PR is merged
  • I have created a matching pull request in the Documentation repository
  • I intend to create a matching pull request in the Documentation repository after this PR is merged

Tests

  • My changes do not need new tests
  • All tests I have added are passing
  • I have written tests but need help to make them pass
  • I have not written tests and need help to write them

@hughrun hughrun added enhancement New feature or request data About data and metadata management labels Nov 20, 2025
@hughrun
Copy link
Copy Markdown
Member Author

hughrun commented Nov 29, 2025

hmm. Not sure why this NotifyInviteRequest test is failing, I didn't do anything to notifications. I suspect something about ordering/concurrency in the test suite?

@ilkka-ollakka
Copy link
Copy Markdown
Contributor

hmm. Not sure why this NotifyInviteRequest test is failing, I didn't do anything to notifications. I suspect something about ordering/concurrency in the test suite?

I didn't manage to reproduce the failure locally either.

Copy link
Copy Markdown
Contributor

@ilkka-ollakka ilkka-ollakka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good. The failing test is something that could be tried to reproduce but shouldn't block merging in my opinion.

@hughrun
Copy link
Copy Markdown
Member Author

hughrun commented Dec 1, 2025

I can replicate this test failure locally if I run pytest with -n 3 (as per the GitHub action) but not without concurrent tests. I'm guessing there's an underlying problem and this just happens to have surfaced it.

Q object query was wrong.
Also fixed an except block I messed up when merging.
@hughrun hughrun requested a review from mouse-reeve December 14, 2025 08:51
@mouse-reeve
Copy link
Copy Markdown
Member

I have some small tweaks, but I ran into two bugs that weren't obvious to me:

No. 1: If I add a new series with the same name as an existing series, I get this error:

FieldError at /book/18664/confirm

Cannot resolve keyword 'title' into field. Choices are: aasin, absorbed, alternative_names, asin, bnf_id, created_date, finna_key, goodreads_key, id, inventaire_id, isfdb, last_edited_by, last_edited_by_id, librarything_key, libris_key, name, openlibrary_key, origin_id, remote_id, search_vector, seriesbooks, updated_date, user, user_id, viaf, wikidata

Which traces to:
/app/bookwyrm/views/books/edit_book.py, line 378

No. 2: If I try to delete a series using the checkbox on the edit book page, I get this error:

DoesNotExist at /book/18664/edit

SeriesBook matching query does not exist.

Which traces to:
/app/bookwyrm/views/books/edit_book.py, line 74

Copy link
Copy Markdown
Member

@mouse-reeve mouse-reeve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I submitted fixes for all these comments on your repo, hopefully that helps??? But the two errors I found unfortunately remain

* Adds migration files needed for merge

* Sorts series by number

Also fixes a blocktrans error

* Small wording and formatting tweaks to seris view
@hughrun hughrun closed this Feb 3, 2026
@hughrun hughrun reopened this Feb 3, 2026
@hughrun hughrun marked this pull request as draft February 3, 2026 10:04
@mouse-reeve mouse-reeve mentioned this pull request Feb 3, 2026
4 tasks
Copy link
Copy Markdown
Contributor

@dato dato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a look at this PR, I have some minor comments and questions (all suggestions are optional).

Thanks!!

- fix some tests
- remove user/actor from Series
- fix bugs with saving series manually
- turns out we need 'user' on Series as well
- fix reverse values for activitypub
- fix upgrade_series command and add test
- make series a proper ordered collection
- fix various test problems
- prevent duplicate seriesbooks
- fix problems in edit_book template due to series management
- fix issues with series pages
@hughrun hughrun marked this pull request as ready for review February 14, 2026 04:50
@hughrun hughrun requested review from dato and mouse-reeve February 14, 2026 05:27
Copy link
Copy Markdown
Member

@mouse-reeve mouse-reeve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry to be the bearer of this news, but now when I import a book without a series from Inventaire, it creates a blank string series that has a url linked from the book page, but the link leads to a 404

@hughrun
Copy link
Copy Markdown
Member Author

hughrun commented Feb 22, 2026

hmm, that seems suboptimal! I must have broken the logic somewhere.

hughrun added 3 commits March 22, 2026 06:51
- fixes issue where imported books from Inventaire created series with no name
- uses django's get_or_create() for simpler code
- rationalises migrations
- adds tests
@hughrun hughrun requested review from mouse-reeve and removed request for dato March 22, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

data About data and metadata management enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple series to a single book Move series membership from Edition to Work Series are tied to the first-named author in each edition

4 participants