Need a way to store additional information for books for users

I have a “Books” model which stores information about books - name, author, etc. This common database of books is displayed to users on a page. Since there are a lot of books, I want it to be paginated. I want to give users the ability to mark the books they have read, store when they finished reading it, and store how long they read it for. So there’s a list of all the books in the database, and then there are some books that a particular user would have read and stored additional information for. On top of that, for books that someone has read, while displaying books from the database containing all the books, I want to be able to mark the particular books that this particular user has read on the frontend, so I need something telling me that this book has been read by the user browsing the site so that I can go ahead and maybe change the colour of the background. How do I do this?

Hi Aruj,

I would have a close look into the documentation, especially to the “Model Layer” part.

If you want to “link” e.g. books from a model in another table, ForeignKeys are what you are looking for.

If you want to change the appearance of the website based on some information provided by a query, the templates section is what you are looking for.

In case you are new to all that stuff, the Intro Tutorial is a really good point to start at.

In addition to the advice above, I’ll add another suggestion.

Since the impression I’m getting from your post is that you’re really just getting started with this, I’d break this down into individual steps.

You’ve identified about a dozen different features you want implemented. I would suggest you pick one fundamental feature and get it working. After that’s working and tested, then you can add each feature in turn. Don’t try to do this all at once unless you really have an excellent roadmap to get you there.

I’m really sorry guys (@KenWhitesell too), I could have done a much better job at explaining what help I need. I’ll try to do better in the future.

So let’s say I have a “Book” model

class Book(models.Model):
    name = models.CharField(max_length=255)
    author = models.CharField(max_length=255)

Now, this model has a lot of objects. Let’s say we have Book 1, Book 2, Book 3, all the way till Book 10. A User can now choose to mark a Book as read, and enter the time at which they read it. I’m trying to avoid giving each User a copy of every book because I think that’s a lot of wasted memory. What I’m trying to do is, among those N books, (10 in this case), if say the User marked Book 4, then while rendering that list of 10 Books from my views function, I want to somehow be able to retrieve the information “the user accessing the page has read the Book about to displayed”. My current thought is to add an entry to a different model “BookStatus” which is related to an extended User model and each entry stores the time at which a particular book was read. The issue here is that, since I can potentially have a lot of books, I’m using a Paginator (read about it in the docs and don’t know more about it than the basic guide given in the docs) and passing a Page object as context to my HTML template. I don’t see a way to be able to somehow loop over the QuerySet in the Paginator and check for each Book if the current user has read it.

I’m not sure if I’m trying to solve this particular problem in the correct way here. I’m open to ideas on what I could do differently or how I could maybe this idea to work.

The relationship you describe between the Book and User models is a classic ManyToMany using a “through” table.

Your template being used in the page (even though controlled at a “higher level” by the paginator) still has access to every field in the object being rendered. You’re still iterating over a set of objects in the page, the paginator is just controlling which objects you’re rendering. If you’re looking at changing some attribute of the display of an object, it can be done in the template.

Nothing you’ve said so far seems “wrong”. From what I can see, you’re on the right track.

1 Like

Thank you! I read the documentation about the “through” table and it looks like it’s exactly what I need!

Hey, I managed to get this to work using the “through” table. I’m now wondering how I can update the backend using buttons on the frontend. Imagine a list of books displayed on the frontend:

Book1 Author1 (Status Dropdown - has two buttons - to mark the book as “read”/“not read”)
Book2 Author2 (Status Dropdown - has two buttons - to mark the book as “read”/“not read”)
… and so on

I want to be able to make some request to my backend with the information about which book is to be updated and whether I choose the “read” or “not read” button. What’s a good way to do this?

You’ve got a couple different options.

First, the standard Django way to create multiple instances of a form for the same type of object is Django’s formsets. You can create a formset for your through model.

Or, you could use a JavaScript AJAX call to be triggered by an on-change event of each drop-down. That JavaScript would invoke a view to update that field.

The first is a “all-at-once” process - the person would make their selections then submit the formset. The second would be a “per book” process. It would update the record when the drop down is changed.