prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Shelf page json view has a server error
  This is a quick fix, needs a unittest.
  
  --- 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/models/shelf.py`
  Content:
  ```
  1 ''' puttin' books on shelves '''
  2 import re
  3 from django.db import models
  4 
  5 from bookwyrm import activitypub
  6 from .base_model import ActivitypubMixin, BookWyrmModel
  7 from .base_model import OrderedCollectionMixin
  8 from . import fields
  9 
  10 
  11 class Shelf(OrderedCollectionMixin, BookWyrmModel):
  12     ''' a list of books owned by a user '''
  13     name = fields.CharField(max_length=100)
  14     identifier = models.CharField(max_length=100)
  15     user = fields.ForeignKey(
  16         'User', on_delete=models.PROTECT, activitypub_field='owner')
  17     editable = models.BooleanField(default=True)
  18     privacy = fields.CharField(
  19         max_length=255,
  20         default='public',
  21         choices=fields.PrivacyLevels.choices
  22     )
  23     books = models.ManyToManyField(
  24         'Edition',
  25         symmetrical=False,
  26         through='ShelfBook',
  27         through_fields=('shelf', 'book')
  28     )
  29 
  30     def save(self, *args, **kwargs):
  31         ''' set the identifier '''
  32         saved = super().save(*args, **kwargs)
  33         if not self.identifier:
  34             slug = re.sub(r'[^\w]', '', self.name).lower()
  35             self.identifier = '%s-%d' % (slug, self.id)
  36             return super().save(*args, **kwargs)
  37         return saved
  38 
  39     @property
  40     def collection_queryset(self):
  41         ''' list of books for this shelf, overrides OrderedCollectionMixin  '''
  42         return self.books
  43 
  44     def get_remote_id(self):
  45         ''' shelf identifier instead of id '''
  46         base_path = self.user.remote_id
  47         return '%s/shelf/%s' % (base_path, self.identifier)
  48 
  49     class Meta:
  50         ''' user/shelf unqiueness '''
  51         unique_together = ('user', 'identifier')
  52 
  53 
  54 class ShelfBook(ActivitypubMixin, BookWyrmModel):
  55     ''' many to many join table for books and shelves '''
  56     book = fields.ForeignKey(
  57         'Edition', on_delete=models.PROTECT, activitypub_field='object')
  58     shelf = fields.ForeignKey(
  59         'Shelf', on_delete=models.PROTECT, activitypub_field='target')
  60     added_by = fields.ForeignKey(
  61         'User',
  62         blank=True,
  63         null=True,
  64         on_delete=models.PROTECT,
  65         activitypub_field='actor'
  66     )
  67 
  68     activity_serializer = activitypub.AddBook
  69 
  70     def to_add_activity(self, user):
  71         ''' AP for shelving a book'''
  72         return activitypub.Add(
  73             id='%s#add' % self.remote_id,
  74             actor=user.remote_id,
  75             object=self.book.to_activity(),
  76             target=self.shelf.remote_id,
  77         ).serialize()
  78 
  79     def to_remove_activity(self, user):
  80         ''' AP for un-shelving a book'''
  81         return activitypub.Remove(
  82             id='%s#remove' % self.remote_id,
  83             actor=user.remote_id,
  84             object=self.book.to_activity(),
  85             target=self.shelf.to_activity()
  86         ).serialize()
  87 
  88 
  89     class Meta:
  90         ''' an opinionated constraint!
  91             you can't put a book on shelf twice '''
  92         unique_together = ('book', 'shelf')
  93
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py
  --- a/bookwyrm/models/shelf.py
  +++ b/bookwyrm/models/shelf.py
  @@ -39,7 +39,7 @@
       @property
       def collection_queryset(self):
           ''' list of books for this shelf, overrides OrderedCollectionMixin  '''
  -        return self.books
  +        return self.books.all()
   
       def get_remote_id(self):
           ''' shelf identifier instead of id '''
  
verification_info: {"golden_diff": "diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py\n--- a/bookwyrm/models/shelf.py\n+++ b/bookwyrm/models/shelf.py\n@@ -39,7 +39,7 @@\n     @property\n     def collection_queryset(self):\n         ''' list of books for this shelf, overrides OrderedCollectionMixin  '''\n-        return self.books\n+        return self.books.all()\n \n     def get_remote_id(self):\n         ''' shelf identifier instead of id '''\n", "issue": "Shelf page json view has a server error\nThis is a quick fix, needs a unittest.\n", "before_files": [{"content": "''' puttin' books on shelves '''\nimport re\nfrom django.db import models\n\nfrom bookwyrm import activitypub\nfrom .base_model import ActivitypubMixin, BookWyrmModel\nfrom .base_model import OrderedCollectionMixin\nfrom . import fields\n\n\nclass Shelf(OrderedCollectionMixin, BookWyrmModel):\n    ''' a list of books owned by a user '''\n    name = fields.CharField(max_length=100)\n    identifier = models.CharField(max_length=100)\n    user = fields.ForeignKey(\n        'User', on_delete=models.PROTECT, activitypub_field='owner')\n    editable = models.BooleanField(default=True)\n    privacy = fields.CharField(\n        max_length=255,\n        default='public',\n        choices=fields.PrivacyLevels.choices\n    )\n    books = models.ManyToManyField(\n        'Edition',\n        symmetrical=False,\n        through='ShelfBook',\n        through_fields=('shelf', 'book')\n    )\n\n    def save(self, *args, **kwargs):\n        ''' set the identifier '''\n        saved = super().save(*args, **kwargs)\n        if not self.identifier:\n            slug = re.sub(r'[^\\w]', '', self.name).lower()\n            self.identifier = '%s-%d' % (slug, self.id)\n            return super().save(*args, **kwargs)\n        return saved\n\n    @property\n    def collection_queryset(self):\n        ''' list of books for this shelf, overrides OrderedCollectionMixin  '''\n        return self.books\n\n    def get_remote_id(self):\n        ''' shelf identifier instead of id '''\n        base_path = self.user.remote_id\n        return '%s/shelf/%s' % (base_path, self.identifier)\n\n    class Meta:\n        ''' user/shelf unqiueness '''\n        unique_together = ('user', 'identifier')\n\n\nclass ShelfBook(ActivitypubMixin, BookWyrmModel):\n    ''' many to many join table for books and shelves '''\n    book = fields.ForeignKey(\n        'Edition', on_delete=models.PROTECT, activitypub_field='object')\n    shelf = fields.ForeignKey(\n        'Shelf', on_delete=models.PROTECT, activitypub_field='target')\n    added_by = fields.ForeignKey(\n        'User',\n        blank=True,\n        null=True,\n        on_delete=models.PROTECT,\n        activitypub_field='actor'\n    )\n\n    activity_serializer = activitypub.AddBook\n\n    def to_add_activity(self, user):\n        ''' AP for shelving a book'''\n        return activitypub.Add(\n            id='%s#add' % self.remote_id,\n            actor=user.remote_id,\n            object=self.book.to_activity(),\n            target=self.shelf.remote_id,\n        ).serialize()\n\n    def to_remove_activity(self, user):\n        ''' AP for un-shelving a book'''\n        return activitypub.Remove(\n            id='%s#remove' % self.remote_id,\n            actor=user.remote_id,\n            object=self.book.to_activity(),\n            target=self.shelf.to_activity()\n        ).serialize()\n\n\n    class Meta:\n        ''' an opinionated constraint!\n            you can't put a book on shelf twice '''\n        unique_together = ('book', 'shelf')\n", "path": "bookwyrm/models/shelf.py"}], "after_files": [{"content": "''' puttin' books on shelves '''\nimport re\nfrom django.db import models\n\nfrom bookwyrm import activitypub\nfrom .base_model import ActivitypubMixin, BookWyrmModel\nfrom .base_model import OrderedCollectionMixin\nfrom . import fields\n\n\nclass Shelf(OrderedCollectionMixin, BookWyrmModel):\n    ''' a list of books owned by a user '''\n    name = fields.CharField(max_length=100)\n    identifier = models.CharField(max_length=100)\n    user = fields.ForeignKey(\n        'User', on_delete=models.PROTECT, activitypub_field='owner')\n    editable = models.BooleanField(default=True)\n    privacy = fields.CharField(\n        max_length=255,\n        default='public',\n        choices=fields.PrivacyLevels.choices\n    )\n    books = models.ManyToManyField(\n        'Edition',\n        symmetrical=False,\n        through='ShelfBook',\n        through_fields=('shelf', 'book')\n    )\n\n    def save(self, *args, **kwargs):\n        ''' set the identifier '''\n        saved = super().save(*args, **kwargs)\n        if not self.identifier:\n            slug = re.sub(r'[^\\w]', '', self.name).lower()\n            self.identifier = '%s-%d' % (slug, self.id)\n            return super().save(*args, **kwargs)\n        return saved\n\n    @property\n    def collection_queryset(self):\n        ''' list of books for this shelf, overrides OrderedCollectionMixin  '''\n        return self.books.all()\n\n    def get_remote_id(self):\n        ''' shelf identifier instead of id '''\n        base_path = self.user.remote_id\n        return '%s/shelf/%s' % (base_path, self.identifier)\n\n    class Meta:\n        ''' user/shelf unqiueness '''\n        unique_together = ('user', 'identifier')\n\n\nclass ShelfBook(ActivitypubMixin, BookWyrmModel):\n    ''' many to many join table for books and shelves '''\n    book = fields.ForeignKey(\n        'Edition', on_delete=models.PROTECT, activitypub_field='object')\n    shelf = fields.ForeignKey(\n        'Shelf', on_delete=models.PROTECT, activitypub_field='target')\n    added_by = fields.ForeignKey(\n        'User',\n        blank=True,\n        null=True,\n        on_delete=models.PROTECT,\n        activitypub_field='actor'\n    )\n\n    activity_serializer = activitypub.AddBook\n\n    def to_add_activity(self, user):\n        ''' AP for shelving a book'''\n        return activitypub.Add(\n            id='%s#add' % self.remote_id,\n            actor=user.remote_id,\n            object=self.book.to_activity(),\n            target=self.shelf.remote_id,\n        ).serialize()\n\n    def to_remove_activity(self, user):\n        ''' AP for un-shelving a book'''\n        return activitypub.Remove(\n            id='%s#remove' % self.remote_id,\n            actor=user.remote_id,\n            object=self.book.to_activity(),\n            target=self.shelf.to_activity()\n        ).serialize()\n\n\n    class Meta:\n        ''' an opinionated constraint!\n            you can't put a book on shelf twice '''\n        unique_together = ('book', 'shelf')\n", "path": "bookwyrm/models/shelf.py"}]}