•11 months ago
This is the seventh installment of a tutorial series focused on how to create a full-stack application using Flask and Stream. In this article, we will continue to explore creating, updating, and deleting activities by adding content to collections, a group of URLs with available previews. Be sure to check out the Github repo to follow along!
Similar to our user feeds from the last post, our first step will be to create a new “Feed Group” titled “Collections”:
The activities that we will be adding will be considered “content” which will be posted to a “collection”. We want users to be able to follow collections and see updates, so we will be using a flat feed. We can use the feed created from the collection to generate all of the content needed for the page. After the feed is created, a table in our database needs to be made to store the content.
Setting the Table
“Content” will include a URL, a title and description of the link, and fields for the ID, the Stream ID (reference previous article to decide if you need this field), timestamp, and a foreign key column to attach the associated collection.
Content is added to a collection by a user, so we must complete the relationship from the collection model. We also want to avoid adding duplicates, so we will create another class function to check for the existence of a URL within the collection.
To round out our model, we will construct class functions to add, update, and delete content.
As always, since we have changed our database, we will have to update and migrate.
Now that our model is ready, we can start to build the form that will pass through to our template. This form will introduce a “select field” which we will populate with a user’s collections in the view. By default, data passed through a form is rendered as a string, and since our database expects an integer instead, we will coerce the collection field into an integer. The render_kw argument will allow us to pass a list of tuples, containing the collection ID and the name of the collection, to make the selection easier for the end user.
Next, we will build templates for adding, editing, and viewing content. We must create the template for adding content first, using wtf.quick_form().
To edit content, we will add a “permissions-check” to our original template so that the author or admin user can make changes. For your own projects, it is best to integrate a confirmation step when editing or deleting posts to ensure that it is done intentionally (we will touch on this in a future article).
Lastly, we will set up the content view template, which will render the fields from the content, while using the permissions-check to allow editing.
View From The Top
After we design our form, we can now build up the views. The select field element is the new addition to the process at this point. We will dynamically generate the select field box by creating a list of tuples. A select field requires two values: first, the value to return through the form and second, the text to represent the choice. To avoid confusion, the second value will be the name of the collection itself instead of an integer ID value.
We’re done! Now that we have built endpoints to create, read, upload and delete content for our app, we can finalize the process by ensuring that everything is functioning properly. Try it out by creating a new collection and adding your first piece of content!
Now that our content and collections are up and running, I want to spend a little bit of time developing testing functions for the Stream components we have started to use.
The user model should test out adding and editing a user. When a user confirms their account, we add the user to Stream, so the test_valid_confirmation_token() function will need to be updated to use Stream. First, we initialize the Stream client and provide all of the fields Stream will need to create a user. Since the gravatar that we have associated with a user is dependent on their email address, we will have to make a similar change in test_valid_email_change_token(). To make certain that our test does not interfere with “real” data, delete the user after you are finished. If you were putting this testing into a production setting, it is good practice to create replica feeds to avoid any possible complications.
To test all of the components of collections, we will be creating an entirely new file. In this test we will create a user, confirm and add them to Stream and the database, and build a collection for them. We will update the collection before deleting it, and then we will ultimately delete the user, too.
Content will be another file, and we will test all of its components together. I find it helpful to perform tests that overlap to ensure that there are no issues in long chains of events. An example of a thorough test would include a user signing up, building a collection, editing it, creating a new piece of content in that collection and editing that as well. This will provide an end-to-end test of our application functionality.
As always, thanks for reading and happy coding!
Note: The next post in this series can be found here.