CS412
Fall 2025

Assignment 7: User Accounts, Authentication and Registration

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

Learning Objectives

After completing this assignment, students will be able to:


Pre-requisites: Assignments 6

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

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

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 fifth part of the case study.

Here is a sample implementation: MiniInsta part 5.

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 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/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 8.

Overview

Django provides many features “out of the box” and ready to use, along with the ability to customize almost everything. One of the great “out of the box” features is the Django User model and authentication framework. The framework comes built-in, ready to use, with generic view classes, templates, and helper functions.

In task 1, we begin by using the authentication framework with an existing user that is already authenticated (logged in). Once this is working, we can refactor (revise) several of the URLs take advantage of knowing who is logged in.

In task 2, we add login and logout features.

In Task 3, we add registration (creating a User account) to the create Profile process.

Task 1: Authentication with User accounts and constraints on CRUD operations.

  1. Modify the existing Profile model to add a ForeignKey to the standard Django User model (from django.contrib.auth.models). This will associate each Profile with a User for authentication and identification purposes.

    When you make migrations, remember that you will need to set a default value for all existing Profiles – for example, the admin User.

    Note: this is a good use-case for having a one-to-one relationship between Profiles and Users. However, we need a way to migrate existing Profiles that were created without a User. By making this attribute a ForeignKey instead of a OneToOne, we can set a default value for all existing Profiles.

    You will be able to change this later from the Django Admin pages.

    Use the Django admin to create one non-admin user, and associate it with one of the existing Profiles. This will be your “test” User.

Testing Hint: use Incognito Mode

  • It is helpful to test login/logout within a new tab in “Incognito Mode” in the Chrome Browser. Every new Incognito window is by default not authenticated, and does not remember your previous login.

  • It also makes it possible to be logged in as “Admin” in one window and another user in a different window.

  1. Revise the base.html template to account for having an authenticated user.

    It will be helpful to print out (in the web page) which user (if any) is logged in while debugging/building the authentication into the application. You can choose whether to keep it in the final version or not.

  2. Revise the views to require that a user be logged in before they can do anything that would modify the database, i.e., Create, Update, or Delete operations. Also: showing the post feed and doing a search should be constrained only to logged-in users.

    The only operations available to a non-logged-in user should be showing all profiles, showing a profile page, showing a post, showing followers, showing following, and (later) creating a new profile.

    The LoginRequiredMixin base class will handle the authentication for you. Inherit from this class in any view that will require authentication.

    Hint: It might be helpful to create your own subclass of LoginRequiredMixin with any additional features that you find you need, for instance: a method to find/return the Profile logged in user, which will be needed in many subclass views.

    Test each view one by one (by typing the URL), to ensure that the authentication requirement works as expected. That is to say, try doing an update profile without being logged in. It should fail, and require you to authenticate. Make sure that after authenticating, the user is redirected to the appropriate “next” page view, i.e., if the user was trying to create a Post, redirect them to the create post after login.

  3. Review all of the links available from the profile page and navigation links (e.g., at the top or bottom of your page).

    Use decision logic to only display links that should be available to an authenticated User, or when the authenticated User is the one associated with that Profile.

    In particular: only the user associated with a Profile should be allowed to update that Profile, create a Post, delete a Post, update a Post, or view the feed. Hide such links from unauthenticated users.

    That is, the only User who should be allowed to update a Profile, create a Post, update a Post or view the feed is the User associated with the Profile. Other Users, even if they are authenticated, should have “read only” access to the profile page.

  4. Now that we know which User (and Profile) is logged in, we will refactor several of the application’s URL patterns. These patterns:

    • 'profile/<int:pk>/feed'
    • 'profile/<int:pk>/search'
    • 'profile/<int:pk>/update'
    • 'profile/<int:pk>/create_post'

    all required a parameter named pk (the primary key) to identify the Profile for which we wanted to do each respective operation. Now that we require a logged in user, we want to change these URLs to remove the <int:pk>:

    • 'profile/feed'
    • 'profile/search'
    • 'profile/update'
    • 'profile/create_post'

    That is, to remove the primary key from the URL. You will need to update any templates that used the previous URLs to remove the (no longer needed) URL parameter.

    Add another URL pattern, which will be used to show the logged-in user their own profile page:

    • 'profile'

    In the generic view classes, the default way to find the Profile (or any model) object is to use the URL parameter pk to do an object lookup (this is done in the get_object method). Now that we have removed the URL parameter pk, we will need a different way to get the object.

    Revise the view classes that need to find the Profile object (of the logged in user) by implementing their get_object(self) method (to replace the default behavior).

    This method implementation will use the logged in user (self.request.user) and the object manager (Profile.objects) to find and return the Profile corresponding to this User.

    Hint: it will NOT work for Profiles that are still associated with the default User (admin user), i.e., there will be multiple matching Profiles for the default/admin user. There are some simple and some clever work-arounds, and you are welcome to try any reasonable solution. Just be aware that for testing purposes, you should test with a User that is not the admin user.

  5. Test everything! Start at this URL pattern: http://127.0.0.1:8000/mini_insta/.

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: Authentication: Login and logout

Django provides a lot of flexibility for authentication. To begin, we will use the built-in authentication framework which can be used directly in your app’s URLs, and is imported from django.contrib.auth.auth_views

  1. Add two new URLs to your application:

    a. 'login/', which will be implemented by the generic view class auth_views.LoginView.

    b. 'logout/', which will be implemented by the generic view class auth_views.LogoutView

    Create a URL pattern for each one, with a pseudonym to use within your application.

  2. Building the login feature: a tale of three errors and a success.

    a. Specify the login template

    Test out the URL: http://127.0.0.1:8000/mini_insta/login/.

    It should bring an error message, because it cannot find the default template registration/login.html.

    No worries! Create your own login template at mini_insta/templates/mini_insta/login.html. This template will display a pre-made form, provided by auth_views.LoginView. All you need to do is to create the HTML form tags and a submit button, and display the context variable form.

    In your URL pattern, pass a parameter to the .as_view method, to specify the template name to display,

    e.g., auth_views.LoginView.as_view(template_name='mini_insta/login.html')

    b. Specify what to do after login

    Test out the URL: http://127.0.0.1:8000/mini_insta/login/ again. Fill out the form with a valid username/password for your non-admin user, and submit.

    This time, the login should be successful, but after logging in the default behavior is to direct you to the URL: http://localhost:8000/accounts/profile/. You can verify that the login was successful by trying this URL: http://localhost:8000/mini_insta/, which should show that you are in fact logged in. The problem is that we did not specify what to do after the login was successful. You will correct this by adding a hidden form field in the login form, with the name next, and specify the value to contain a valid URL within your application, for example to show all profiles.

    Test out the URL: http://127.0.0.1:8000/mini_insta/login/ again. Fill out the form with username/password and submit.

    This time, you should be logged in AND be redirected after login the page identified by the URL in next. Good job.

    d. Specify the login_url

    Test out the URL: http://127.0.0.1:8000/mini_insta/profile/update. The UpdateProfileView should identify that you need to log in before accessing the view.

    This time, expect a page not found error because the URL http://localhost:8000/accounts/login/, which is the default URL within a Django project for the login feature.

    To provide a specialized login URL, you must implement the get_login_url method on the view class (either on each view class that needs it, or in your subclass of LoginRequiredMixin). This method must return the URL to the application’s login (i.e., described in your urlpatterns). Implement this get_login_url method, and ... you guessed it: test it again!

  3. The logout feature is much simpler!

    Test out the URL: http://localhost:8000/mini_insta/logout/.

    Note: in the newest version of Django, the auth_views.LogoutView will not allow a GET request. A link created with the <a> tag always sends a GET request. To send a POST request, you will need to create a small <form> with the method set to POST.

    It should log you out on the first try!

    However, after log out, you are directed to a default “Logged out” page, which is not part of your mini_insta app, does not follow your styling scheme, and contains a link to “Log in again” – to the admin app.

    To customize this behavior, you could create a template mini_insta/templates/mini_insta/logged_out.html which will provide a “log out confirmation” page. Include on this page a link to log in again (to the mini_insta app). To show this template, you will need a simple view (try: TemplateView), and then a URL (e.g., logout_confirmation) to bring up that view.

    In your URL pattern, pass a parameter to the .as_view method, to specify the template name to display, e.g., auth_views.LogoutView.as_view(next_page='logout_confirmation')

    Try logging in again, and logging out again, until you are satisfied that it works.

  4. In the base.html template, add navigation links for login and logout.

    Use decision logic to show/hide the navigation URLs depending on which User is logged in.

    That is to say:

    • A user who is not logged in should be able to see all profiles and login.

    • A user who is logged in should have a link to see their own profile page, as well as a link to log out.

  5. Test everything again!

Important: Add files to git!

  • You’ve 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: User registration and creating Profiles

Registration is the process of creating a User account. We need to set the User as a foreign key on the Profile instance, so the User is a pre-requisite for creating a Profile.

There are several valid ways to accomplish this and no canonical “correct” solution.

When a user wants to create a Profile, some options include:

For simplicity, we will chose the last option: showing the user 2 forms at once, and having them submit both forms together.

Note as well that we do not want to include the User in the CreateProfileForm, as this would create a situation in which the client would pick a User from a drop-down list. Instead, we will assign the User to the profile programmatically.

  1. In the forms.py file, define a class CreateProfileForm which inherits from forms.ModelForm. Use this form to create the attributes for username, display_name, bio_text, and image_url.

  2. Create a template create_profile_form.html to define an HTML form, display the CreateProfileForm.

    Hint it might be helpful to use your update_profile_form.html as a starting point.

  3. Define a CreateProfileView class, which inherits from the generic CreateView.

    Override the get_context_data(self, **kwargs) method as follows:

    • Begin by calling the superclass version of this method, and saving the context dictionary to a local variable.

    • Create an instance of the UserCreationForm (from django.contrib.auth.forms), and store this instance in the context data. Call it whatever you like, but remember the name so you can find it in the template.

    Define a URL http://127.0.0.1:8000/mini_insta/create_profile, and associate it with the CreateProfileView. Add a link to this URL into the navigation links, to be displayed when there is no logged-in user.

  4. Modify your create_profile_form.html template, to display the additional form (UserCreationForm) within the same HTML form as your CreateProfileForm.

    Example: http://cs-webapps.bu.edu/azs/cs412/mini_insta5/create_profile.

    Test this out in your browser, to see that it displays the fields from the UserCreationForm: Username, Password and Password confirmation, along with the fields from the CreateProfileForm.

  5. In the CreateProfileView class’ form_valid method, you will need to:

    • Reconstruct the UserCreationForm instance from the self.request.POST data

    • Call the save() method on the UserCreationForm instance. This method call will return the newly created User object. Save it to a variable user.

    • Log the User in (hint: use the built-in function django.contrib.auth.login). You will need to specify as parameters the HTTP request, the user to log in, and the authentication back-end (database) to use. For example:

      login(self.request, user, backend='django.contrib.auth.backends.ModelBackend')
      
    • Attach the Django User to the Profile instance object (form.instance) so that it can be saved to the database.

    • Delegate the rest to the super class’ form_valid method.

  6. Test it out! Start at this URL pattern: http://127.0.0.1:8000/mini_insta/create_profile.

    It will probably fail several times. This is a normal part of the process!

    It will be helpful to have an Incognito Window open with the admin logged in, so you can check if/when Django User(s) are created, and delete the User between tests.

Important: Add files to git!

  • You’ve 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: Implementing Likes and Follows

OK! Now that we have authenticated users, we can distinguish between the Profile of the logged-in-user and the Profile being displayed. This distinction makes it possible to do some operations that use both Profiles together.

For example:

In this section, you have a lot of discretion about how to implement these operations to create Likes and Follows. Your application must support the following URL patterns:

In each case the “logged in user” will be the one taking actions, and will either follow or unfollow the “other” Profile or Post.

You must create view classes (or functions) to implement each of these operations. A suggestion (that you are not required to follow) is to use the TemplateView class, and override the dispatch method to implement each operation. In these views, you will need to find both the “logged in user” Profile and the other Profile, and then use the appropriate ORM operations to create (or delete)Like or Follow objects.

You may choose what user interface to use, for example a “Follow” button on the profile or a Like button or icon next to a Post. The only firm constraint is to not allow a Profile to follow itself (i.e., hide this user interface), and do not allow a Profile to like it’s own Post.

Optional Challenge

For some additional work, add a feature to be able to create Comments on a Post. This feature is similar to adding a Like on a Post, except that it will require some additional form processing.

The feature should require a logged-in user, and have a simple user interface to create a Comment on an existing Post (e.g., in the feed). After adding a Comment, the user should be redirected to view the Post on which they have commented.


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_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. Create a text file called sample_user.txt, containing a valid username and password with which we can test your app.

  3. 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_url.txt"`
    

    Push it to GitHub, using

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

    In the Gradescope upload page, upload these two files:

    • mini_url.txt

    • github_url.txt

    • sample_user.txt

Notes: