Assignment 7: User Accounts, Authentication and Registration
- Assignment 7: User Accounts, Authentication and Registration
- Learning Objectives
- Case Study: Mini Insta
- Preliminaries
- Continue working on the mini_insta Application
- Overview
- Task 1: Authentication with User accounts and constraints on CRUD operations.
- Task 2: Authentication: Login and logout
- Task 3: User registration and creating Profiles
- Task 4: Implementing Likes and Follows
- Optional Challenge
- Deployment to cs-webapps
- Submitting Your Work
due by 9:00 p.m. EDT on Friday 10/24/2025
Learning Objectives
After completing this assignment, students will be able to:
-
Implement authentication and permissions within a web application.
-
Incorporating user accounts into application data models and work flows.
-
Revise/refactor URL routing and page views to create a user-based experience.
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:
- Viewing, creating, and updating user profiles
- Viewing and creating posts
- Uploading images
- Viewing and adding followers
- Developing a feed to show posts from Profiles one is following
- Incorporating user accounts, authentication (login), and registration
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.
-
Modify the existing
Profilemodel to add aForeignKeyto the standard DjangoUsermodel (fromdjango.contrib.auth.models). This will associate eachProfilewith aUserfor 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 adminUser.Note: this is a good use-case for having a one-to-one relationship between
Profiles andUsers. However, we need a way to migrate existingProfiles that were created without aUser. By making this attribute aForeignKeyinstead of aOneToOne, we can set a default value for all existingProfiles.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.
-
Revise the
base.htmltemplate 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.
-
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
LoginRequiredMixinbase 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
LoginRequiredMixinwith any additional features that you find you need, for instance: a method to find/return theProfilelogged 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. -
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 authenticatedUseris the one associated with thatProfile.In particular: only the user associated with a
Profileshould be allowed to update thatProfile, create aPost, delete aPost, update aPost, or view the feed. Hide such links from unauthenticated users.That is, the only
Userwho should be allowed to update aProfile, create aPost, update aPostor view the feed is theUserassociated with theProfile. OtherUsers, even if they are authenticated, should have “read only” access to the profile page. -
Now that we know which
User(andProfile) 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 theProfilefor 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 parameterpkto do an object lookup (this is done in theget_objectmethod). Now that we have removed the URL parameterpk, we will need a different way to get the object.Revise the view classes that need to find the
Profileobject (of the logged in user) by implementing theirget_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 theProfilecorresponding to thisUser.Hint: it will NOT work for
Profiles that are still associated with the defaultUser(admin user), i.e., there will be multiple matchingProfiles 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 aUserthat is not the admin user. -
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
-
Add two new URLs to your application:
a.
'login/', which will be implemented by the generic view classauth_views.LoginView.b.
'logout/', which will be implemented by the generic view classauth_views.LogoutViewCreate a URL pattern for each one, with a pseudonym to use within your application.
-
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 byauth_views.LoginView. All you need to do is to create the HTML form tags and a submit button, and display the context variableform.In your URL pattern, pass a parameter to the
.as_viewmethod, 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 namenext, and specify thevalueto 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_urlTest out the URL:
http://127.0.0.1:8000/mini_insta/profile/update. TheUpdateProfileViewshould identify that you need to log in before accessing the view.This time, expect a
page not founderror because the URLhttp://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_urlmethod on the view class (either on each view class that needs it, or in your subclass ofLoginRequiredMixin). This method must return the URL to the application’s login (i.e., described in yoururlpatterns). Implement thisget_login_urlmethod, and ... you guessed it: test it again! -
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.LogoutViewwill not allow aGETrequest. A link created with the<a>tag always sends aGETrequest. To send aPOSTrequest, you will need to create a small<form>with themethodset toPOST.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_instaapp, 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.htmlwhich 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_viewmethod, 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.
-
In the
base.htmltemplate, add navigation links for login and logout.Use decision logic to show/hide the navigation URLs depending on which
Useris 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.
-
-
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:
-
Have them register first (create a Django
User), ask them to login, and then send them to the create profile page. -
Have them register first (create Django
User), log them in automatically, and then send them back to the create profile page. -
Have them fill out two forms at once: the
UserCreationForm(to create the DjangoUser) as well as theCreateProfileForm, and submit both forms at once.
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.
-
In the
forms.pyfile, define a classCreateProfileFormwhich inherits fromforms.ModelForm. Use this form to create the attributes forusername,display_name,bio_text, andimage_url. -
Create a template
create_profile_form.htmlto define an HTML form, display theCreateProfileForm.Hint it might be helpful to use your
update_profile_form.htmlas a starting point. -
Define a
CreateProfileViewclass, which inherits from the genericCreateView.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(fromdjango.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 theCreateProfileView. Add a link to this URL into the navigation links, to be displayed when there is no logged-in user. -
-
Modify your
create_profile_form.htmltemplate, to display the additional form (UserCreationForm) within the same HTML form as yourCreateProfileForm.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,PasswordandPassword confirmation, along with the fields from theCreateProfileForm. -
In the
CreateProfileViewclass’form_validmethod, you will need to:-
Reconstruct the
UserCreationForminstance from theself.request.POSTdata -
Call the
save()method on theUserCreationForminstance. This method call will return the newly createdUserobject. Save it to a variableuser. -
Log the
Userin (hint: use the built-in functiondjango.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
Userto theProfileinstance object (form.instance) so that it can be saved to the database. -
Delegate the rest to the super class’
form_validmethod.
-
-
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 theUserbetween 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:
-
The “logged in user” can like a
Postby anotherProfile. -
The “logged in user” can search for other
Posts orProfiles, and view the profile of another user. The “logged in user” can chose to follow the otherProfile.
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:
profile/<int:pk>/followprofile/<int:pk>/delete_followpost/<int:pk>/likepost/<int:pk>/delete_like
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
- Deploy your web application to the
cs-webapps.bu.edu.
Follow the deployment instructions here.
-
Test your web application on
cs-webapps.bu.eduto ensure that everything works correctly. -
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!
-
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.
-
Create a text file called
sample_user.txt, containing a valid username and password with which we can test your app. -
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.txtin the root of your project (e.g.,djangodirectory). 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`
-
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:
-
Upload these files to Gradescope before the deadline.
-
When you upload, the autograder script will process your file(s).
-
You may resubmit as many times as you like before the deadline, and only the grade from the last submission will be counted.