CS412
Spring 2025

Assignment 7: Web Application with Models and Forms

due by 9:00 p.m. EDT on Friday, March 7, 2025

Learning Objectives

After completing this assignment, students will be able to:


Pre-requisites: Assignments 6

Assignment 7 builds upon the case study you began in Assignment 6.

You must have completed Assignment 6 before you attempt Assignment 7.

This assignment requires the Python Imaging Library, Pillow to be installed. If you have not already installed it in your virtual environment do so now:

    # pipenv install Pillow

Case Study: Mini Facebook

This assignment is part of an in-depth case study to develop a data-enabled web application. In the entire case-study, you will simulate the core features of the Facebook social networking application:

This assignment is the fifth part of the case study, and you will continue the work from the previous assignment to build a database-enabled web application. , including these same solutions. It is safe to view these sites.

Here is a sample implementation (tasks 1 and 2): MiniFacebook Application.

Here is a sample implementation (tasks 3 and 4): MiniFacebook Application.

You do not need to match the data of this example, or even the way it is formatted. The look and feel of the application, as well as the data you display, is entirely up to you.

Preliminaries

In your work on this assignment, make sure to abide by the collaboration policies of the course.

If you have questions while working on this assignment, please post them on Piazza! This is the best way to get a quick response from your classmates and the course staff.

For each problem in this problem set, we will be writing or evaluating some Python code. You are encouraged to use the VS Code IDE which will be discuss/presented in class, but you are welcome to use another IDE if you choose.

Important Guidelines: Comments and Docstrings

  • Refer to the class Coding Standards for important style guidelines. The grader will be awarding/deducting points for writing code that conforms to these standards.

  • Every program file must begin with a descriptive header comment that includes your name, username/BU email, and a brief description of the work contained in the file.

  • Every function must include a descriptive docstring that explains what the function does and identifies/defines each of the parameters to the function.


Continue working on the mini_fb Application

Continue to do this work within your existing Django project, within the mini_fb. application that you worked on in Assignment 6.

Task 1: Defining an Image model and displaying Images on the profile page.

  1. Create a new data model called Image, which encapsulates the idea of an image file (not a URL) that is stored in the Django media directory and some meta-data about that image file.

    The Image class should include the following attributes: the profile (the foreign key to indicate the relationship to the Profile of the user who uploaded this Image; the image_file, which is the ImageField being stored, the timestamp of when it was uploaded, and an optional caption that describes what’s in the Image.

    For now, we want to create Images as part of writing a StatusMessage, but we want to keep the possibility of having Images that are not tied to a StatusMessage, e.g., as a profile picture (that does not relate to a StatusMessage). Therefore, we will not store a foreign key to the StatusMessage.

    In general, a StatusMessage could have zero to many Images.
    To model this relationship, create another model called StatusImage.

    The StatusImage will have 2 foreign keys: to the image and the status_message. That is, a StatusMessage provides a way to find Images that relate to a StatusMessage, and vice versa, to find the StatusMessage to which an Image is related.

    Here is a diagram of the models and their relationships:

    Recall that after you change models, you will need to run the makemigrations script and the migrate command to update your database.

    Important:

    • Before you can go on to step 2 (displaying a StatusMessage with Images), you will need to add at least 1 Image (and maybe even 2) to your database using the admin tool to upload the file.

    • When you add an Image to the database, you will need to also associate it with a StatusImage object, to create the relationship with a StatusMessage. Take note of which StatusMessage (for which Profile) this is, so that you can test that the Image(s) display properly (see below).

  2. Displaying a StatusMessage that includes one or more Images.

    The simplest way to access the Images associated with a StatusMessage is to add an accessor method (get_images) to the StatusMessage model.

    This get_images method should use the ORM to find all Images that are related to this StatusMessage, and then return a list or QuerySetof those Image(s). The QuerySet could be empty if there are no Images related to this StatusMessage.

    In your show_profile.html template, you will need to update the code that displays status messages to include displaying images (if they exist).

    With the addition of optional images, some (but not all) status messages will contain images, while others will not. You can handle this by adding a for loop in the template.

    For example:

    {% for img in status.get_images %}
    <img src='{{img.image_file.url}}' alt='{{img.image_file.url}}'>
    {% endfor %}
    

    where status is the name of StatusMessage object and img.image_file is the name of the Image attribute containing the ImageField.

    Important: what variable names to use?

    • We do not know what context variable name you used for your status messages! You chose this name in your code! In the example above, we use the name status, but this will only work if you also used the name status. You must be consistent.

    • We do not know what attribute name you used for the ImageField within your Image model. You chose this name in your model definition! In the example above, we use the name image_file, but this will only work if you also used the name image_file. You must be consistent.

  3. Test everything! Start at this URL pattern: 'http://127.0.0.1:8000/mini_fb/. Go to a profile which contains a status message with an image. Verify that the image displays on the profile page.

Important: Add files to git!

  • You’ve just modified your database structure, and added some data records.

  • This is an excellent time to add your files to git, commit your changes, and push your changes to GitHub before anything gets F@&#ed up.

Task 2: Creating a StatusMessage with one (or multiple) Image(s).

In this task, we want to actually upload an image file (or several image files) as part of creating a StatusMessage.

There are many ways to accomplish this, and hopefully this is the simplest way. Search Google or StackOverflow and you will find several complicated ways!

The general strategy is to add the image files to the same HTML form that creates the StatusMessage, and then add some special processing in the CreateStatusMessageView to create/save the Image objects.

  1. Edit your create_status_form.html template to add a form field to the HTML form as follows:

     <input type="file" name = "files" multiple />
    

    The input type="file" will allow you to use a file selection dialog (in the browser) to select one or multiple files. These will be sent to the server using the name files and we will process it as a list (even if it only contains one image file).

    • Add the following attribute to the form tag: enctype="multipart/form-data" to indicate that this form might include file submission (image) data.

    • TEST that your form displays the file upload button.

  2. In the CreateStatusMessageView, you will need to modify the form_valid method to handle the uploading of files as follows:

    • Save the form, which will store the new StatusMessage object to the database, and return a reference to this new object, e.g.,

      # save the status message to database
      sm = form.save()
      

      Note that the variable sm is a reference to the new StatusMessage object.

    • Read the multi-part form data into a python variable, e.g.,

      # read the file from the form:
      files = self.request.FILES.getlist('files')
      
    • For each file in files, you will need to:

      • Create an Image object, and set the file into the Image‘s ImageField attribute, and call the Image‘s .save() method to save the Image object to the database.

      • Create and save a StatusImage object that sets the foreign keys of the StatusMessage and the Image objects, and then call the StatusImage object’s .save() method to save the Image object to the database.

    These operations will probably fail the first time you try them! That’s normal! Use this as an opportunity to practice your debugging skills by instrumenting your code to include good tracing (i.e., print statements) to help you figure out what data you have and where you have an error.

  3. Test everything! Start at this URL pattern: 'http://127.0.0.1:8000/mini_fb/. Go to any profile, and then use the status message form to upload an image. Test that the image gets stored in Django, and finally that it displays on the profile page.

Important: Add files to git!

  • You’ve just reached a good stopping point.

  • This is an excellent time to add your files to git, commit your changes, and push your changes to GitHub before anything gets F@&#ed up.

Task 3: Updating an existing Profile

  1. Create a new form class UpdateProfileForm which inherits from forms.ModelForm.

    Be sure to specify the inner-class Meta, which relates this form to the Profile model. Also, specify the list of fields that this form should set (i.e., all of the data attributes of the Profile class, except NOT the user’s first name or last name, which should not be changeable).

  2. Create a class-based view called UpdateProfileView, which inherits from the generic UpdateView class. Be sure to specify the form this create view should use, i.e., the UpdateProfileForm. Also, specify the name of the template to use to render this form, which must be called mini_fb/update_profile_form.html.

  3. Create the template file mini_fb/update_profile_form.html, to render the HTML form.

    You may use your discretion/imagination about how this template should display the form fields, but you must include labels for each field to show what input is expected. Upon submission, your form will be handled by the generic UpdateView class, which will update the Profile record for this model and store the update in the database.

    On this page, include a ‘cancel’ button, which should stop the update operation and return to the profile page.

  4. Edit the mini_fb project’s urls.py file. Create a URL mapping to route requests from the URL pattern 'profile/<int:pk>/update' to the UpdateProfileView view. Name this URL update_profile.

    Test your URL! Try this URL pattern: 'http://127.0.0.1:8000/mini_fb/profile/1/update (or a similar URL with a different primary key).

    You should see a form to update the profile, and it should be pre-filled with the existing data for this Profile record. Change something in the form, and use the submit button to submit it to the server.

    Upon submission you should be routed back to the profile page, on which you should see the update.

    If you have errors, resolve them now before continuing on to the next part.

    Finally, add an Update Profile link to the show_profile.html template, so that you can click that link and reach the update form.

Important: Add files to git!

  • You’ve just reached a good stopping point.

  • This is an excellent time to add your files to git, commit your changes, and push your changes to GitHub before anything gets F@&#ed up.

Task 4: Updating and Deleting StatusMessages

In this part, you will create a way for to the user to update or delete a status message. This will involve:

For example, notice the links for update and delete:

These buttons (actually links that look like buttons) link will connect to the URLs for the UpdateStatusMessaseView and DeleteStatusMessageView, respectively.

Tasks

Continue to do this work within your existing Django project, within the mini_fb application.

  1. Create a class DeleteStatusMessageView, which inherits from the generic DeleteView class. This base class will do most of what we want, but we will need to override some methods below. Set the model, template_name and context_object_name attributes as you have done in the past when using other generic views.

    Override the get_success_url(self) method, to return the URL to which the user should be redirected after a successful delete operation. Specifically, when a StatusMessage is deleted, the user should be redirected to the profile page for whom the status message was deleted.

  2. Create the template file delete_status_form.html. This file will have 2 small forms:

    • One to confirm the delete. It will send a POST back to the same URL at which you are trying to do the delete.

    • One to cancel the delete. It will send a GET to URL to redisplay the profile page.

      Hint: you will need to set the action attribute of the form to the URL to show the profile page. You will need to create a URL that returns to the profile page, but you have created this URL elsewhere in your code. Think about where you did this previously!

    For example:

  3. Create a new URL pattern to trigger the delete status message process. Use this URL pattern: status/<int:pk>/delete, and associate this URL with your DeleteStatusMessageView class.

    A concrete example of such a URL would be:

    http://localhost:8000/mini_fb/status/11/delete

    which means to delete the status message with primary key of 11.

  4. Within your show_profile.html template, update the code that displays status messages. You will need to add a link (titled delete) for each status message. Within this link, you will need to create the correct URL pattern to trigger the URL defined in the previous step.

    {% url 'delete_status' st_msg.pk %}
    

    where st_msgis the name of StatusMessage object within the loop that displays the status messages.

  5. Test that the new delete link works – it should show up in the profile page, once for each status message. Now try to click the link. Check that it generates the correct URL (for example: http://localhost:8000/mini_fb/status/11/delete). If it does not generate a correct URL for the delete operation, go back and fix that now.

  6. Repeat steps 1-5 for the update operation. Create a class UpdateStatusMessageView which inherits from the generic UpdateView class, create a template called update_status_form.html with confirmation/cancel options, and a URL pattern: status/<int:pk>/update, and associate this URL with your UpdateStatusMessageView class.

    The requirement for the update status feature is to be able to update the text of the StatusMessage.

    Optional Challenge

    StatusMessages could 0 to many Images associated with them. For additional challenge, make it possible to add/remove Images from a StatusMessage. Hint: try working on deleting Images first (one at a time), and then try adding additional Images (one or several at a time).

  7. Test everything!!

Important: Add files to git!

  • You’ve just reached a good stopping point.

  • This is an excellent time to add your files to git, commit your changes, and push your changes to GitHub before anything gets F@&#ed up.

Deployment to cs-webapps

  1. Deploy your web application to the cs-webapps.bu.edu.

Follow the [deployment instructions here][deployment].

  1. Test your web application on cs-webapps.bu.edu to ensure that everything works correctly.

  2. Resolve any deployment issues.


Submitting Your Work

10 points; will be assigned by the autograder, verifying that you have submitted the correct files/URL, and testing that you website exists at the specified URL. 90 points; will be testing your application and code review

Log in to GradeScope to submit your work.

Be sure to name your files correctly!

  1. Create a text file within your main django directory called a7_url.txt, containing the URL to your web page, and nothing else.

    For example: https://cs-webapps.bu.edu/azs/cs412/mini_fb/.

    This file will be used by the autograder to locate your web page, so you must get the URL exactly correct, and you must not include any other text or code in the file.

  2. Add teaching staff as collaborators to your GitHub repository (wderocco8, Aanuszkiewicz, and azs-bu). Read-only access is fine.

    Create a text file called github_url.txt in the root of your project (e.g., django directory). Paste your GitHub URL in the file.

    Add these files to your git repository using

    `git add -A`.
    

    Commit this to your git repository, using

    `git commit -m "Added a7_url.txt"`
    

    Push it to GitHub, using

    `git push origin main`
    
  3. Log in to GradeScope to submit your work.

    In the Gradescope upload page, upload these two files:

    • a7_url.txt

    • github_url.txt

Notes: