Well, you reduced everything mod ord('z'), as if the alphabet's internal values were zero-based. As you've discovered, this is not the case. Instead, you need to make that overflow check, and then subtract the width of your data set. The basic logic is
if ord(chr) + key > ord('z'):
result = ord(chr) + key - 26
Is that enough to get you moving?
You can also do this with a simple translation table, building a new alphabet from the old: cut the first 3 characters and append them to the back of your translation string:
blank_code = 'abcdefghijklmnopqrstuvwxyz'
new_code = blank_code[-n:] + blank_code[:n]
This gives you a corresponding "alphabet" to use. Also see the translate
method for a quick way to use these.