Assignment 7: Web Application with Models and Forms
- Assignment 7: Web Application with Models and Forms
- Learning Objectives
- Case Study: Mini Facebook
- Preliminaries
- Continue working on the mini_fb Application
- Task 1: Defining an Image model and displaying Images on the profile page.
- Task 2: Creating a StatusMessage with one (or multiple) Image(s).
- Task 3: Updating an existing Profile
- Task 4: Updating and Deleting StatusMessages
- Deployment to cs-webapps
- Submitting Your Work
due by 9:00 p.m. EDT on Friday, March 7, 2025
Learning Objectives
After completing this assignment, students will be able to:
-
Use the Django ImageField to store and retrieve image files and their associated database records.
-
Use HTML forms to upload a image files to Django, including setting foreign keys to create 1-to-many relationships.
-
Use HTML forms to display images stored in the Django media directory.
-
Implement update and delete operations by inheriting from generic views, and creating appropriate URL routing in response to update and delete operations.
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:
- Viewing, creating, and updating user profiles
- Viewing and creating status messages
- Uploading images
- Viewing and adding friends
- Developing a news feed to show status messages from multiple friends
- Incorporating user accounts, authentication, and registration
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 Image
s on the profile page.
-
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: theprofile
(the foreign key to indicate the relationship to theProfile
of the user who uploaded thisImage
; theimage_file
, which is theImageField
being stored, thetimestamp
of when it was uploaded, and an optionalcaption
that describes what’s in theImage
.For now, we want to create
Image
s as part of writing aStatusMessage
, but we want to keep the possibility of havingImage
s that are not tied to aStatusMessage
, e.g., as a profile picture (that does not relate to aStatusMessage
). Therefore, we will not store a foreign key to theStatusMessage
.In general, a
StatusMessage
could have zero to manyImage
s.
To model this relationship, create another model calledStatusImage
.The
StatusImage
will have 2 foreign keys: to theimage
and thestatus_message
. That is, aStatusMessage
provides a way to findImage
s that relate to aStatusMessage
, and vice versa, to find theStatusMessage
to which anImage
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 themigrate
command to update your database.Important:
-
Before you can go on to step 2 (displaying a
StatusMessage
withImage
s), you will need to add at least 1Image
(and maybe even 2) to your database using theadmin
tool to upload the file. -
When you add an
Image
to the database, you will need to also associate it with aStatusImage
object, to create the relationship with aStatusMessage
. Take note of whichStatusMessage
(for whichProfile
) this is, so that you can test that theImage
(s) display properly (see below).
-
-
Displaying a
StatusMessage
that includes one or moreImage
s.The simplest way to access the
Image
s associated with aStatusMessage
is to add an accessor method (get_images
) to theStatusMessage
model.This
get_images
method should use the ORM to find allImage
s that are related to thisStatusMessage
, and then return alist
orQuerySet
of thoseImage
(s). TheQuerySet
could be empty if there are noImage
s related to thisStatusMessage
.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 ofStatusMessage
object andimg.image_file
is the name of theImage
attribute containing theImageField
.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 namestatus
. You must be consistent. -
We do not know what attribute name you used for the
ImageField
within yourImage
model. You chose this name in your model definition! In the example above, we use the nameimage_file
, but this will only work if you also used the nameimage_file
. You must be consistent.
-
-
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.
-
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 namefiles
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.
-
-
In the
CreateStatusMessageView
, you will need to modify theform_valid
method to handle the uploading of files as follows:-
Save the
form
, which will store the newStatusMessage
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 newStatusMessage
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 theImage
‘sImageField
attribute, and call theImage
‘s.save()
method to save theImage
object to the database. -
Create and save a
StatusImage
object that sets the foreign keys of theStatusMessage
and theImage
objects, and then call theStatusImage
object’s.save()
method to save theImage
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. -
-
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
-
Create a new form class
UpdateProfileForm
which inherits fromforms.ModelForm
.Be sure to specify the inner-class
Meta
, which relates this form to theProfile
model. Also, specify the list offields
that this form should set (i.e., all of the data attributes of theProfile
class, except NOT the user’s first name or last name, which should not be changeable). -
Create a class-based view called
UpdateProfileView
, which inherits from the genericUpdateView
class. Be sure to specify the form this create view should use, i.e., theUpdateProfileForm
. Also, specify the name of the template to use to render this form, which must be calledmini_fb/update_profile_form.html
. -
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 theProfile
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.
-
Edit the
mini_fb
project’surls.py
file. Create a URL mapping to route requests from the URL pattern'profile/<int:pk>/update'
to theUpdateProfileView
view. Name this URLupdate_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 theshow_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 StatusMessage
s
In this part, you will create a way for to the user to update or delete a status message. This will involve:
-
Links next to the status message labeled
update
anddelete
. -
A view to handle the each of these operations.
-
A template to show a confirm/cancel option (form).
-
A
url
to trigger each operation.
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.
-
Create a class
DeleteStatusMessageView
, which inherits from the genericDeleteView
class. This base class will do most of what we want, but we will need to override some methods below. Set themodel
,template_name
andcontext_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 aStatusMessage
is deleted, the user should be redirected to the profile page for whom the status message was deleted. -
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:
-
-
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 yourDeleteStatusMessageView
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.
-
Within your
show_profile.html
template, update the code that displays status messages. You will need to add a link (titleddelete
) 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_msg
is the name ofStatusMessage
object within the loop that displays the status messages. -
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. -
Repeat steps 1-5 for the update operation. Create a class
UpdateStatusMessageView
which inherits from the genericUpdateView
class, create a template calledupdate_status_form.html
with confirmation/cancel options, and a URL pattern:status/<int:pk>/update
, and associate this URL with yourUpdateStatusMessageView
class.The requirement for the update status feature is to be able to update the text of the
StatusMessage
.Optional Challenge
StatusMessage
s could 0 to manyImage
s associated with them. For additional challenge, make it possible to add/removeImage
s from aStatusMessage
. Hint: try working on deletingImage
s first (one at a time), and then try adding additionalImage
s (one or several at a time). -
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
- Deploy your web application to the
cs-webapps.bu.edu
.
Follow the [deployment instructions here][deployment].
-
Test your web application on
cs-webapps.bu.edu
to 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
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.
-
Add teaching staff as collaborators to your GitHub repository (
wderocco8
,Aanuszkiewicz
, andazs-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`
-
Log in to GradeScope to submit your work.
In the Gradescope upload page, upload these two files:
-
a7_url.txt
-
github_url.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.