Collect less
Why it matters Data you never collect cannot leak, cannot be stolen, cannot be misused later and never needs deleting. The cheapest privacy work on any site is a shorter form. In this exercise you trim a real-looking sign-up form down to what the product actually uses.
When you rent a bike, the shop needs your phone number in case you vanish with the bike. It does not need your birthday, your job or your mother's maiden name. A form that asks for those is not being thorough; it is collecting things that can only cause trouble.
Data minimisation: collecting only the data a feature really needs, keeping it only as long as it needs it, and storing the answer instead of the raw data when the answer is enough.
Three questions for every field
- Which feature uses it? If you cannot name one the product has today, drop the field. "Might be useful one day" is not a feature.
- Does it need to be required? A delivery phone number can be optional. Required fields push people to type fake data, which helps nobody.
- Can you keep the answer instead? To check that someone is old enough, you need a yes or no, not their date of birth. Work out the answer at sign-up and store only that.
Working with dates in Python
Dates in forms usually arrive as text like "2009-03-14" (year, month, day). The standard library turns them into date objects you can compare:
from datetime import date
born = date.fromisoformat("2009-03-14")
today = date.fromisoformat("2026-10-30")
print(born.year, born.month, born.day) # 2009 3 14Age in whole years is the difference in years, minus one if this year's birthday has not happened yet. Comparing (month, day) pairs does that check neatly, because Python compares tuples item by item:
had_birthday = (today.month, today.day) >= (born.month, born.day)
age = today.year - born.year - (0 if had_birthday else 1)
print(age) # 17Python treats True as 1 and False as 0 in arithmetic, so today.year - born.year - ((today.month, today.day) < (born.month, born.day)) is the same thing in one line.
A common misconception: "we can hash the birth date to make it safe". There are only about 36,500 dates in a century, so a computer can hash every one and match yours in a blink. You saw this with hashed emails in Leg 2. If you only need "old enough", keep only that.
In other languages
// JavaScript
function isOldEnough(birth, today, minAge) {
const b = new Date(birth), t = new Date(today);
let age = t.getUTCFullYear() - b.getUTCFullYear();
if (t.getUTCMonth() < b.getUTCMonth() ||
(t.getUTCMonth() === b.getUTCMonth() && t.getUTCDate() < b.getUTCDate())) age--;
return age >= minAge;
}// C#
int age = today.Year - born.Year;
if (today < born.AddYears(age)) age--;
bool oldEnough = age >= minAge;# Django: keep only the answer
class Account(models.Model):
email = models.EmailField(unique=True)
old_enough = models.BooleanField() # no birth_date column at allRecap
- Every field needs a feature the product has today; otherwise drop it.
- Store the answer (old enough: yes) instead of the raw data (the birth date) when the answer is enough.
- Hashing small sets such as dates does not protect them.
ShopD Kitchen sells online cooking classes. Its sign-up form, FIELDS, has eight fields; each says which features would use it ("needed_by"). The product really has only the features in FEATURES, and classes are for people aged MIN_AGE or over. Write three functions:
keep_fields(fields, features): return the list of field"name"s, in the original order, whose"needed_by"list shares at least one feature withfeatures.is_old_enough(birth_date, today, min_age): both dates are text like"2009-03-14". ReturnTrueif the person's age in whole years ontodayis at leastmin_age(someone whose birthday is today has just turned the new age).clean_signup(form, kept, today, min_age):formis a dict of what someone typed. Return a new dict with only the keys that are inkept, except that"birth_date"is never stored: if it is kept, store"old_enough"(the result ofis_old_enough) in its place.
This lesson is locked
Lessons open one at a time. Finish the previous lesson to unlock this one.