CS412
Fall 2025

Assignment 4: Using Multiple Models; Creating Model Data

due by 9:00 p.m. EDT on Friday 10/3/2025

Learning Objectives

After completing this assignment, students will be able to:


Pre-requisites: Assignments 3

Assignment 4 builds upon the case study you began in Assignment 3.

You must have completed Assignment 3 before you begin Assignment 4.

Case Study: Mini Insta

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 Instagram social networking application. Over the course of 5 parts, you will implement:

This assignment is the second part of the case study.

Here is a sample implementation: MiniInsta part 2.

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 dispaly, 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 comforms 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/method 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_insta Application

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

Task 1: Modeling and Displaying Posts and Photos

  1. Create a new model called Post, which will model the data attributes of an Instagram post. This Post model will need to include the following data attributes:

    • profile (the foreign key to indicate the relationship to the Profile of the creator of this post)
    • timestamp (the time at which this post was created/saved)
    • caption (the optional text associated with this post)

    Here is a diagram of the models and their relationships:

    The foreign key is how we model a relationship between different kinds of objects. In this case, we are defining the relationship such that every Post object is related to a single Profile object.

    Be sure to create a __str__ method on this class to return a string representation of this object.

  2. Create a new model called Photo, which will model the data attributes of an image associated with a Post. This Photo model will need to include the following data attributes:

    • post (the foreign key to indicate the relationship to the Post to which this Photo is associated.
    • image_url (a valid URL to an image stored on the public world-wide web)
    • timestamp (the time at which this Photo was created/saved)

    Here is a diagram of the models and their relationships:

    The foreign key is how we model a relationship between different kinds of objects. In this case, we are defining the relationship such that every Photo object is related to a single Post object.

    Be sure to create a __str__ method on this class to return a string representation of this object.

  3. Use the Django admin to create some sample data:

    • Create 3 sample Posts, for at least 2 different Profiles, with any content/captions of your choosing.

    • Create at least 3 sample Photos, associated with 2 different Posts. That is: at least one Post should have more than one Photo.

  4. Create accessor methods to retrieve related model data.

    • In the Profile class, define an accessor method get_all_posts to find and return all Posts for a given Profile. The return type will be a QuerySet containing Posts.

    • In the Post class, define an accessor method get_all_photos to find and return all Photos for a given Post.
      The return type will be a QuerySet containing Photos.

    Hint: Use the object manager to filter Post objects by their profile (foreign key), and order them by timestamp.

  5. Edit your show_profile.html template to add the display of Posts.

    For each Post, you should display the first Photo associated with that Post. If there is no Photo associated with the Post, display an alternate image indicating that there is “no image.”

  6. Create a view, template, and URL pattern to display a single Post.

    The view should be called PostDetailView, and the template should be called show_post.html. The URL pattern should be in the form: 'http://127.0.0.1:8000/mini_insta/post/<int:pk>', where <int:pk> will be replaced by the primary key for the Post being shown.

    On the page to show the post, display the post caption and timestamp, as well as all Photos associated with this Post. You may choose how to arrange these on the page, for example using a table or div elements within a grid layout.

    Finally, on the show_profile_page.html template, add a link from each Post to retrieve it’s detail page.

  7. Test your page! Try this URL pattern: 'http://127.0.0.1:8000/mini_insta/. Follow the link to any profile that has posts, and view that 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 2: Creating a new Post

In this Task, you will create a form to collect inputs to create a new Post. For example:

  1. Within the mini_insta application folder, create the new file forms.py. In this file, add the following import statements at the top:

    from django import forms
    from .models import *
    

    Create a class CreatePostForm which inherits from forms.ModelForm. Be sure to specify the inner-class Meta, which relates this form to the Post model.

    Also, specify the list of fields that this form should set (i.e., the data attributes of the Post class).

Note: How Django displays HTML Form Fields

  • By default, Django will choose which type of HTML form fields to use, based on the data types of the fields in your model.

    For example, when your form has a model.TextField, Django will use a <textarea> (multi-line text input box). Often, this is OK. For this assignment it is fine, and you can get full functionality and points using the defaults.

  • If you want to customize how the HTML form displays, you can explicitly tell Django which type of form field to use.

  • See the details in the Django Forms Documentation page.

  1. Create the template file mini_insta/create_post_form.html, to render the HTML form. Your form must:

    • define the <form> tags, and set the form’s method to POST
    • include the django-created csrf_token as a form field (as you did in the example video)
    • provide a submit button and a cancel button
    • do not include the Profile as one of the fields in this form. It looks awkward on the screen, and anyway the profile will be specified by the URL which will process the creation of the Post.

    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 CreateView class, which will create a new record for this model and store it in the database.

    Important design notes:

    Recall that Photos are stored separately from Posts, which is required to enable the “one post can have many photos” relationship. As a consequence, we will need a way to include the important information for a Photo (i.e., its image_url attribute), which is not part of the Post object. To do this, add an explicit HTML form field for the image_url to the form. We will return to this in a future assignment to enable (a) uploading images instead of specifying the URL and (b) handling multiple images instead of just one. For now, we will use an image_url and assume creating one single Photo per Post.

  2. Edit the file views.py to add a view called CreatePostView to handle the form submission. We will again use the generic CreateView as a base class, but it will require some additional work that was not required in the pre-class example.

    Specifically, the Post requires a foreign key to relate it to a Profile object, and a Photo requires a foreign key to relate it to a Post object. We will return to these below. For now, set up the template_name and form_class.

    Create a URL mapping to route requests from the URL pattern 'profile/<int:pk>/create_post', associate it with the CreatePostView, and name this URL create_post.

    Note: there are several ways to go about solving the issue of attaching the foreign key to the Post object. These instructions walk you through one approach using the generic CreateView.

    First Complication: Implementing get_context_data method

    Try this URL: http://127.0.0.1:8000/mini_insta/profile/1/create_post. (Use another primary key if you have no object numbered 1).

    You should be able to display the create_post_form.html template. When you try submitting it, it gets complicated.

    When you try to create the submission URL (the form action), you will need to provide the parameter profile.pk (i.e., identifying the Profile to which this Post corresponds) as part of that URL.

    To have access to this as a context variable, you will need to implement the special method get_context_data on the CreatePostView class.

    There is a special attribute called self.kwargs, which is accessible within the methods on the CreateView and its subclasses. self.kwargs is a dictionary containing any URL parameters, and the value self.kwargs['pk'] is the primary key of the Profile corresponding to the URL pattern.

    In the get_context_data method: begin with the context dictionary from the superclass. Find the Profile object (corresponding to self.pk), add the Profile object (call the context variable profile, for consistency with how things worked on other pages). Now you will have access to the context variable profile within the create_post_form.html template. Use the profile.pk to help generate the URL to which the form should be submitted, e.g., the form action 'http://127.0.0.1:8000/mini_insta/profile/1/create_post'.

    Second complication: Implementing the form_valid method

    Test out this URL again. You should now be able to display/submit the create_post_form.html. create_post_form.html template. When you try to submit the form, you should see an error that NOT NULL constraint failed: mini_insta_post.profile_id. Basically, you cannot create/save a Post without setting the profile attribute.

    To solve this problem, you will need to write some custom code within the CreatePostView class, to attach the Profile to the Post before submission. Implement the method form_valid on the CreatePostView class to: (a) look up the Profile object by its pk. You can find this pk in self.kwargs['pk']. (b) attach this object to the profile attribute of the post. Now you will be able to save the Post successfully.

    Also in the form_valid method: use the data from the request.POST object to create a new Photo for this post, and set the post attribute as a foreign key (on the Photo).

    After successfully creating a Post, Django should automagically redirect you to the page to show that post (i.e., the DetailView associated with class Post. )

    Finally: be sure to include a “cancel” or “back” button to be able to navigate from the “create post” page back to the “profile” page.

  3. Edit the base.html template, and add a link to the bottom-of-screen navigation, to bring up the create_post page (in its own page view).

    Note: to be able to create a Post, we need to know the profile for whom the Post should be created. This is only possible if the profile is part of the context data for the page. Use decision-logic to show/not show this navigation button as appropriate (i.e., only when you have a profile in the context data.)

  4. Testing!! Start at your main /mini_insta URL, and pick any existing profile. You should see the profile page, with a form to post a post. Write something witty in the form, and use the submit button to submit it to the server.

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.

  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 mini_insta_url.txt, containing the URL to your web page, and nothing else.

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

    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 the teaching staff as collaborators to your GitHub repository with bu-cs412. 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 mini_insta_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:

    • mini_insta_url.txt

    • github_url.txt

Notes: