рдЗрд╕ рдЧрд╛рдЗрдб рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдПрдХ рдХрд╛рдлреА рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧрд┐рдВрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдореМрд▓рд┐рдХрддрд╛ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдореЗрдВ рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред
рд╕рд╛рдордЧреНрд░реА рдХреА рддрд╛рд▓рд┐рдХрд╛
рднрд╛рдЧ 2: рдЯреЗрдореНрдкрд▓реЗрдЯ
рднрд╛рдЧ 3: рдкреНрд░рдкрддреНрд░
рднрд╛рдЧ 4: рдбреЗрдЯрд╛рдмреЗрд╕
рднрд╛рдЧ 5: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд▓реЙрдЧрд┐рди
рднрд╛рдЧ 6: рдкреНрд░реЛрдлрд╛рдЗрд▓ рдкреЗрдЬ рдФрд░ рдЕрд╡рддрд╛рд░
рднрд╛рдЧ 7: рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг (рдпрд╣ рд▓реЗрдЦ)
рднрд╛рдЧ 8: рдЕрдиреБрдпрд╛рдпреА, рд╕рдВрдкрд░реНрдХ рдФрд░ рдорд┐рддреНрд░
рднрд╛рдЧ 9: рдЕрдВрдХреБрд░рдг
рднрд╛рдЧ 10: рдкреВрд░реНрдг рдкрд╛рда рдЦреЛрдЬ
рднрд╛рдЧ 11: рдИрдореЗрд▓ рд╕рдорд░реНрдерди
рднрд╛рдЧ 12: рдкреБрдирд░реНрдирд┐рд░реНрдорд╛рдг
рднрд╛рдЧ 13: рддрд┐рдерд┐ рдФрд░ рд╕рдордп
рднрд╛рдЧ 14: I18n рдФрд░ L10n
рднрд╛рдЧ 15: рдЕрдЬрд╛рдХреНрд╕
рднрд╛рдЧ 16: рдбрд┐рдмрдЧрд┐рдВрдЧ, рдкрд░реАрдХреНрд╖рдг рдФрд░ рдкреНрд░реЛрдлрд╛рдЗрд▓рд┐рдВрдЧ
рднрд╛рдЧ 17: рд▓рд┐рдирдХреНрд╕ рдкрд░ рддреИрдирд╛рддреА (рдФрд░ рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдкрд░ рднреА!)
рднрд╛рдЧ 18: рд╣рд░реЛрдХреВ рдХреНрд▓рд╛рдЙрдб рдкрд░ рддреИрдирд╛рддреА
рднрд╛рдЧ 3: рдкреНрд░рдкрддреНрд░
рднрд╛рдЧ 4: рдбреЗрдЯрд╛рдмреЗрд╕
рднрд╛рдЧ 5: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд▓реЙрдЧрд┐рди
рднрд╛рдЧ 6: рдкреНрд░реЛрдлрд╛рдЗрд▓ рдкреЗрдЬ рдФрд░ рдЕрд╡рддрд╛рд░
рднрд╛рдЧ 7: рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг (рдпрд╣ рд▓реЗрдЦ)
рднрд╛рдЧ 8: рдЕрдиреБрдпрд╛рдпреА, рд╕рдВрдкрд░реНрдХ рдФрд░ рдорд┐рддреНрд░
рднрд╛рдЧ 9: рдЕрдВрдХреБрд░рдг
рднрд╛рдЧ 10: рдкреВрд░реНрдг рдкрд╛рда рдЦреЛрдЬ
рднрд╛рдЧ 11: рдИрдореЗрд▓ рд╕рдорд░реНрдерди
рднрд╛рдЧ 12: рдкреБрдирд░реНрдирд┐рд░реНрдорд╛рдг
рднрд╛рдЧ 13: рддрд┐рдерд┐ рдФрд░ рд╕рдордп
рднрд╛рдЧ 14: I18n рдФрд░ L10n
рднрд╛рдЧ 15: рдЕрдЬрд╛рдХреНрд╕
рднрд╛рдЧ 16: рдбрд┐рдмрдЧрд┐рдВрдЧ, рдкрд░реАрдХреНрд╖рдг рдФрд░ рдкреНрд░реЛрдлрд╛рдЗрд▓рд┐рдВрдЧ
рднрд╛рдЧ 17: рд▓рд┐рдирдХреНрд╕ рдкрд░ рддреИрдирд╛рддреА (рдФрд░ рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдкрд░ рднреА!)
рднрд╛рдЧ 18: рд╣рд░реЛрдХреВ рдХреНрд▓рд╛рдЙрдб рдкрд░ рддреИрдирд╛рддреА
рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐
рдЗрд╕ рдЧрд╛рдЗрдб рдХреЗ рдкрд┐рдЫрд▓реЗ рд╣рд┐рд╕реНрд╕реЛрдВ рдореЗрдВ, рд╣рдордиреЗ рдзреАрд░реЗ-рдзреАрд░реЗ рдЕрдкрдиреЗ рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧрд┐рдВрдЧ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛, рдЪрд░рдг рджрд░ рдЪрд░рдг рдирдИ рд╕реБрд╡рд┐рдзрд╛рдПрдБ рдЬреЛрдбрд╝рддреЗ рд╣реБрдПред рдЗрд╕ рд╕рдордп рддрдХ, рд╣рдорд╛рд░рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдФрд░ рдЕрдзрд┐рдХреГрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЙрдиреНрд╣реЗрдВ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдореЗрдВ рдЕрдкрдирд╛ рдбреЗрдЯрд╛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреА рднреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
рдЖрдЬ рд╣рдо рдирдИ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреЛ рдирд╣реАрдВ рдЬреЛрдбрд╝реЗрдВрдЧреЗред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд▓рд┐рдЦрд┐рдд рдХреЛрдб рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд╕реНрдерд┐рд░ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдврд╛рдВрдЪрд╛ рднреА рдмрдирд╛рдПрдВрдЧреЗ, рдЬреЛ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рд╣рдореЗрдВ рд╕рдВрднрд╛рд╡рд┐рдд рджреБрд░реНрдШрдЯрдирд╛рдУрдВ рдХреЛ рд░реЛрдХрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ред
рдмрдЧ рдЦреЛрдЬ
рдкрд┐рдЫрд▓реЗ рдЕрдзреНрдпрд╛рдп рдХреЗ рдЕрдВрдд рдореЗрдВ, рдореИрдВрдиреЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдХрд┐ рдХреЛрдб рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реИред рдЕрдм рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ рдФрд░ рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдЗрд╕ рддрд░рд╣ рдХреА рдЪреАрдЬреЛрдВ рдкрд░ рдХреИрд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред
рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЙрдкрдирд╛рдореЛрдВ рдХреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЙрдкрдирд╛рдо рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЪреБрдирд╛ рдЧрдпрд╛ рд╣реИред рдпрджрд┐ OpenID рдкреНрд░рджрд╛рддрд╛ рд╣рдореЗрдВ рдЙрдкрдирд╛рдо рдмрддрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЕрдиреНрдпрдерд╛, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдИрдореЗрд▓ рдХреЗ рдкрд╣рд▓реЗ рднрд╛рдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрдкрдирд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдПрдХ рд╣реА рдЙрдкрдирд╛рдо рд╡рд╛рд▓реЗ рджреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкрдВрдЬреАрдХрд░рдг рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХреЗрд╡рд▓ рдкрд╣рд▓рд╛ рд╣реА рд╕рдлрд▓ рд╣реЛрдЧрд╛ред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдХрд░, рд╣рдордиреЗ рдЗрд╕реЗ рдХреЗрд╡рд▓ рдмрджрддрд░ рдмрдирд╛ рджрд┐рдпрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣рд╛рдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЯрдХрд░рд╛рд╡ рд╕реЗ рдмрдЪрдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред
рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдЗрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░реЗрдВ, рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВ рдХрд┐ рдЬрдм рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реЛрддреА рд╣реИ, рддреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреИрд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддрд╛ рд╣реИред
рдлреНрд▓рд╛рд╕реНрдХ рдореЗрдВ рдбрд┐рдмрдЧрд┐рдВрдЧ
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдирдпрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдмрдирд╛рдПрдВред рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рд▓рд┐рдирдХреНрд╕ рд╣реИ:
rm app.db ./db_create.py
рд╡рд┐рдВрдбреЛрдЬ:
del app.db flask/Scripts/python db_create.py
рдмрдЧ рдЦреЗрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рджреЛ OpenID рдЦрд╛рддреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдпрд╣ рдмреЗрд╣рддрд░ рд╣реИ рдпрджрд┐ рдпреЗ рдЦрд╛рддреЗ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рджрд╛рддрд╛рдУрдВ рд╕реЗ рд╣реИрдВ, рдЕрдиреНрдпрдерд╛ рдХреБрдХреАрдЬрд╝ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдХрдард┐рдирд╛рдЗрдпрд╛рдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред рддреЛ, рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
- рдЕрдкрдиреЗ рдкрд╣рд▓реЗ рдЦрд╛рддреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЙрдЧ рдЗрди рдХрд░реЗрдВред
- рдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдбрд┐рдЯ рдкреЗрдЬ рдкрд░, рдЙрдкрдирд╛рдо рдХреЛ 'dup' рдореЗрдВ рдмрджрд▓реЗрдВ
- рд▓реЙрдЧ рдЖрдЙрдЯ рдХрд░реЗрдВ
- рдЕрдкрдиреЗ рджреВрд╕рд░реЗ рдЦрд╛рддреЗ рд╕реЗ рдкреНрд░рд╡реЗрд╢ рдХрд░реЗрдВ
- рдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдбрд┐рдЯ рдкреЗрдЬ рдкрд░, рдЙрдкрдирд╛рдо рдХреЛ 'dup' рдореЗрдВ рдмрджрд▓реЗрдВ
рдКрдкреНрд╕! рд╣рдореЗрдВ sqlalchemy рдХреЗ рдХрд╛рд░рдг рдЕрдкрд╡рд╛рдж рдорд┐рд▓рд╛ред рддреНрд░реБрдЯрд┐ рдкрд╛рда рдкрдврд╝рддрд╛ рд╣реИ:
sqlalchemy.exc.IntegrityError IntegrityError: (IntegrityError) UNIQUE constraint failed: user.nickname u'UPDATE user SET nickname=?, about_me=? WHERE user.id = ?' (u'dup', u'', 2)
рдиреАрдЪреЗ рдЗрд╕ рддреНрд░реБрдЯрд┐ рдХрд╛ рдПрдХ рд╕реНрдЯреИрдХ рдЯреНрд░реЗрд╕ рд╣реИ , рдЬрд┐рд╕рдореЗрдВ рдЖрдк рди рдХреЗрд╡рд▓ рдкреНрд░рддреНрдпреЗрдХ рдлреНрд░реЗрдо рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдХреЛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐ рдЕрдкрдиреЗ рдХреЛрдб рдХреЛ рд╕реАрдзреЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ!
рддреНрд░реБрдЯрд┐ рд╡рд┐рд╡рд░рдг рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЕрд╕рд╛рдЗрди рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдЙрдкрдирд╛рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╣реИред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐
User
рдореЙрдбрд▓ рдореЗрдВ,
nickname
рдлрд╝реАрд▓реНрдб
unique=True
рд░реВрдк рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╣реА рд╡рдЬрд╣ рд╣реИ рдХрд┐ рдпрд╣ рд╕реНрдерд┐рддрд┐ рдЙрддреНрдкрдиреНрди рд╣реБрдИред
рдЗрд╕ рддреНрд░реБрдЯрд┐ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдФрд░ рд╕рдорд╕реНрдпрд╛ рд╣реИред рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рддреНрд░реБрдЯрд┐ (рдпрд╣ рдпрд╛ рдХреЛрдИ рдЕрдиреНрдп) рд╣реЛрддреА рд╣реИ, рддреЛ рдЙрд╕реЗ рддреНрд░реБрдЯрд┐ рдХрд╛ рд╡рд┐рд╡рд░рдг рдФрд░ рд╕рдВрдкреВрд░реНрдг рдЯреНрд░реЗрд╕рдмреИрдХ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ред рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди рдпрд╣ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐рд╕реА рдФрд░ рдХреЛ рдирд╣реАрдВ рдЪрд╛рд╣реЗрдВрдЧреЗред
рдЗрд╕ рд╕рдордп, рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдиреЗ рд░рд┐рд▓реАрдЬрд╝ рдореЛрдб рдореЗрдВ рдХрд╛рдо рдХрд┐рдпрд╛ред рдпрд╣ рдореЛрдб рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдкрд░
debug=True
run
рдкрджреНрдзрддрд┐ рдХреЗ рд▓рд┐рдП рджрд┐рдпрд╛ рдЧрдпрд╛
debug=True
рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдХреНрд░рд┐рдп рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЬрдм рд╣рдо рд▓рдбрд╝рд╛рдИ рд╕рд░реНрд╡рд░ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛ рдХрд┐ рдбрд┐рдмрдЧрд┐рдВрдЧ рдореЛрдб рдмрдВрдж рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдФрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ (
runp.py
file) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ :
#!flask/bin/python from app import app app.run(debug = False)
рдЕрдм рдЗрд╕ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЪрд▓рд╛рдПрдВ
./runp.py
рджреВрд╕рд░реЗ рдЦрд╛рддреЗ рдХреЗ рдЙрдкрдирд╛рдо рдХреЛ рдлрд┐рд░ рд╕реЗ 'рдбрд┐рдк' рдореЗрдВ рдмрджрд▓рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред рдЗрд╕ рдмрд╛рд░ рд╣рдо рдПрдХ рд╡рд┐рд╕реНрддреГрдд рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдирд╣реАрдВ рджреЗрдЦреЗрдВрдЧреЗред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдореЗрдВ
500 Internal Server Error
рдХреЛрдб рдХреЗ рд╕рд╛рде рдПрдХ HTTP рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИред рдпрд╣ рдлреНрд▓рд╛рд╕реНрдХ рдкреЗрдЬ рддрдм рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдбрд┐рдмрдЧрд┐рдВрдЧ рдореЛрдб рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдЕрдкрд╡рд╛рдж рд╣реЛрддрд╛ рд╣реИред рдкреГрд╖реНрда рдРрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХрдо рд╕реЗ рдХрдо рд╣рдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдирд╛рд╡рд╢реНрдпрдХ рд╡рд┐рд╡рд░рдг рдкреНрд░рдХрдЯ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред
рдлрд┐рд░ рднреА, рд╣рдо рджреЛ рдФрд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рд╛рдордирд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, 500 рддреНрд░реБрдЯрд┐ рдкреГрд╖реНрда рдмрджрд╕реВрд░рдд рджрд┐рдЦрддрд╛ рд╣реИред рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдЬреНрдпрд╛рджрд╛ рдЧрдВрднреАрд░ рд╣реИред рдпрджрд┐ рд╕рдм рдХреБрдЫ рд╡реИрд╕рд╛ рд╣реА рд░рд╣ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╣рдо рдХрднреА рдирд╣реАрдВ рдЬрд╛рди рдкрд╛рдПрдВрдЧреЗ рдХрд┐ рдХреИрд╕реЗ рдФрд░ рдХрдм рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛрддреА рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╕рднреА рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдЕрдм рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИрдВред рд╕реМрднрд╛рдЧреНрдп рд╕реЗ, рдЗрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдмрд╣реБрдд рд╕рд░рд▓ рд╕рдорд╛рдзрд╛рди рд╣реИрдВред
рдореВрд▓ HTTP рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд░
рдлреНрд▓рд╛рд╕реНрдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкреГрд╖реНрдареЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдЕрдкрдиреЗ рдкреГрд╖реНрдареЛрдВ рдХреЛ рекрежрек рдФрд░ релрежреж рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рд╛рдордирд╛ рдХрд░рддреЗ рд╣реИрдВред рдЕрдиреНрдп рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЗ рдЕрдкрдиреЗ рдкреГрд╖реНрда рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдареАрдХ рдЙрд╕реА рддрд░рд╣ рд╣реЛрдЧреАред
рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ
errorhandler
рдбреЗрдХреЛрд░реЗрдЯрд░ (рдлрд╝рд╛рдЗрд▓
app/views.py
errorhandler
) рдХреА
app/views.py
:
@app.errorhandler(404) def not_found_error(error): return render_template('404.html'), 404 @app.errorhandler(500) def internal_error(error): db.session.rollback() return render_template('500.html'), 500
рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдЗрд╕ рдХреЛрдб рдХреЛ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХреЗрд╡рд▓ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдпрд╣рд╛рдБ
db.session.rollback()
ред рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЕрдкрд╡рд╛рдж рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдпрджрд┐ рдЕрдкрд╡рд╛рдж рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдореЗрдВ рддреНрд░реБрдЯрд┐ рдХреЗ рдХрд╛рд░рдг рд╣реБрдЖ рдерд╛, рддреЛ рд╣рдореЗрдВ рд╡рд░реНрддрдорд╛рди рд╕рддреНрд░ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
404 рддреНрд░реБрдЯрд┐ рдХреЗ рд▓рд┐рдП рдЯреЗрдореНрдкреНрд▓реЗрдЯ:
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <h1>File Not Found</h1> <p><a href="{{url_for('index')}}">Back</a></p> {% endblock %}
рдФрд░ рддреНрд░реБрдЯрд┐ 500 тАЛтАЛрдХреЗ рд▓рд┐рдП рдПрдХ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рднреА:
<!-- extend base layout --> {% extends "base.html" %} {% block content %} <h1>An unexpected error has occurred</h1> <p>The administrator has been notified. Sorry for the inconvenience!</p> <p><a href="{{url_for('index')}}">Back</a></p> {% endblock %}
рджреЛрдиреЛрдВ рд╣реА рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рд╣рдо рдЕрднреА рднреА рдореВрд▓ рдкреЗрдЬ рдХреЗ рд░реВрдк рдореЗрдВ
base.html
рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рджреЛрдиреЛрдВ HTTP рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рд╣рдорд╛рд░реЗ рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧ рдХреЗ рдмрд╛рдХреА рдкреГрд╖реНрдареЛрдВ рдХреЗ рд╕рдорд╛рди рд╢реИрд▓реА рдореЗрдВ рджрд┐рдЦрддреЗ рд╣реИрдВред
рдореЗрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рднреЗрдЬрдирд╛
рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рджреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдПрд░рд░ рд░рд┐рдкреЛрд░реНрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рд╕реЗрдЯ рдХрд░реЗрдВрдЧреЗред рд╣рд░ рдмрд╛рд░ рддреНрд░реБрдЯрд┐ рд╣реЛрдиреЗ рдкрд░ рдкрд╣рд▓рд╛ рдИрдореЗрд▓ рд╣рдореЗрдВ рднреЗрдЬреЗрдЧрд╛ред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдореЗрдВ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдФрд░ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рдкреНрд░рд╢рд╛рд╕рдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред (
config.py
) :
# mail server settings MAIL_SERVER = 'localhost' MAIL_PORT = 25 MAIL_USERNAME = None MAIL_PASSWORD = None # administrator list ADMINS = ['you@example.com']
рдмреЗрд╢рдХ, рдЖрдкрдХреЛ рдЗрди рдореВрд▓реНрдпреЛрдВ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдлреНрд▓рд╛рд╕реНрдХ рдкрд╛рдпрдерди рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реЗ
logging
рдореЙрдбреНрдпреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдИрдореЗрд▓ рдкрд░ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреА рд╕реНрдерд╛рдкрдирд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реЛрдЧреА (
app/__init__.py
) :
from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD if not app.debug: import logging from logging.handlers import SMTPHandler credentials = None if MAIL_USERNAME or MAIL_PASSWORD: credentials = (MAIL_USERNAME, MAIL_PASSWORD) mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT), 'no-reply@' + MAIL_SERVER, ADMINS, 'microblog failure', credentials) mail_handler.setLevel(logging.ERROR) app.logger.addHandler(mail_handler)
рдпрджрд┐ рдбрд┐рдмрдЧрд┐рдВрдЧ рдореЛрдб рдмрдВрдж рд╣реИ рддреЛ рд╣рдо рдХреЗрд╡рд▓ рдпреЗ рдИрдореЗрд▓ рднреЗрдЬреЗрдВрдЧреЗред рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдирд╣реАрдВ рд╣реИ рддреЛ рдпрд╣ рдареАрдХ рд╣реИред рд╣рдорд╛рд░реЗ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, SMTP рдбрд┐рдмрдЧ рд╕рд░реНрд╡рд░, рдЬреЛ рдкрд╛рдпрдерди рд╣рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рдХрд╛рдлреА рдЙрдкрдпреБрдХреНрдд рд╣реИред рдЗрд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХрдВрд╕реЛрд▓ рдореЗрдВ рдЯрд╛рдЗрдк рдХрд░реЗрдВ (рдпрд╛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдкрд░ рдпрджрд┐ рдЖрдк рдПрдХ Windows рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реИрдВ):
python -m smtpd -n -c DebuggingServer localhost:25
рдЙрд╕рдХреЗ рдмрд╛рдж, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рджреНрд╡рд╛рд░рд╛ рднреЗрдЬреЗ рдЧрдП рд╕рднреА рдкрддреНрд░реЛрдВ рдХреЛ рд╕реАрдзреЗ рдХрдВрд╕реЛрд▓ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред (рдиреЛрдЯред рдЖрдк рдПрдХ рдмреЗрд╣рдж рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ SMTP рд╕рд░реНрд╡рд░ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рдЬреНрдЮрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ - рдореЗрд▓рдХреИрдЪрд░ ред рдпрд╣ рд╡рд┐рдзрд┐ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рд▓рд┐рдП рд░реВрдмреА рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред)
рдХрд┐рд╕реА рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рдирд╛
рдореЗрд▓ рдореЗрдВ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХрднреА-рдХрднреА рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рд╣рдореЗрдВ рдЯреНрд░реЗрд╕реЗрдХрдмреИрдХ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдФрд░ рдлрд┐рд░ рд▓реЙрдЧ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧреАред
рд╕реЗрдЯрдЕрдк рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдмрд╣реБрдд рдХреБрдЫ рд╡реИрд╕рд╛ рд╣реА рд╣реИ рдЬреИрд╕рд╛ рд╣рдордиреЗ рд╕рд┐рд░реНрдл рдореЗрд▓ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдерд╛ (рдлрд╝рд╛рдЗрд▓
app/__init__.py
)
if not app.debug: import logging from logging.handlers import RotatingFileHandler file_handler = RotatingFileHandler('tmp/microblog.log', 'a', 1 * 1024 * 1024, 10) file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')) app.logger.setLevel(logging.INFO) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.info('microblog startup')
рд▓реЙрдЧ рдХреЛ
tmp
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ
microblog.log
рдирд╛рдо рд╕реЗ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред рд╣рдордиреЗ
RotatingFileHandler
рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЬреЛ рдЖрдкрдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдбреЗрдЯрд╛ рдХреА рдорд╛рддреНрд░рд╛ рдкрд░ рдПрдХ рд╕реАрдорд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЖрдХрд╛рд░ рдПрдХ рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рддрдХ рд╕реАрдорд┐рдд рд╣реИ, рдФрд░ рдЕрдВрддрд┐рдо рджрд╕ рдлрд╛рдЗрд▓реЗрдВ рд╕рд╣реЗрдЬреА рдЧрдИ рд╣реИрдВред
logging.Formatter
рдХреНрд▓рд╛рд╕ рд▓реЙрдЧ рдПрдВрдЯреНрд░реАрдЬ рдХреЗ рд▓рд┐рдП рдПрдХ рдордирдорд╛рдирд╛ рдкреНрд░рд╛рд░реВрдк рд╕реЗрдЯ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдо рд╕рдВрднрд╡ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд╣рдо рд╕рдВрджреЗрд╢ рдХреЛ рдЦреБрдж рд╣реА рд╕рд╣реЗрдЬ рд▓реЗрдВрдЧреЗ, рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк , рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рдХреА рд╕реНрдерд┐рддрд┐, рд╕рд╛рде рд╣реА рдлрд╝рд╛рдЗрд▓ рдирд╛рдо рдФрд░ рд▓рд╛рдЗрди рдирдВрдмрд░ рдЬрд╣рд╛рдВ рд╕реЗ рд░рд┐рдХреЙрд░реНрдбрд┐рдВрдЧ рд╢реБрд░реВ рдХреА рдЧрдИ рдереАред
рд▓реЙрдЧ рдХреЛ рдЕрдзрд┐рдХ рдЙрдкрдпреЛрдЧреА рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рджреЛрдиреЛрдВ
app.logger
рдФрд░
file_handler
рдореЗрдВ рд▓реЙрдЧрд┐рдВрдЧ рдХреЗ рд╕реНрддрд░ рдХреЛ рдХрдо рдХрд░рддреЗ рд╣реИрдВ, рдпрд╣ рд╣рдореЗрдВ рди рдХреЗрд╡рд▓ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд░рд┐рдХреЙрд░реНрдб рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, рдмрд▓реНрдХрд┐ рдЕрдиреНрдп рдЬрд╛рдирдХрд╛рд░реА рднреА рдЬреЛ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдо рдЖрд╡реЗрджрди рдХреЗ рдкреНрд░рд╛рд░рдВрдн рд╕рдордп рдХреЛ рд░рд┐рдХреЙрд░реНрдб рдХрд░реЗрдВрдЧреЗред рдЕрдм, рд╣рд░ рдмрд╛рд░ рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧ рдХреЛ рдбрд┐рдмрдЧрд┐рдВрдЧ рдореЛрдб рдХреЗ рдмрд┐рдирд╛ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕ рдИрд╡реЗрдВрдЯ рдХреЛ рд▓реЙрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╣рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рд╣рдорд╛рд░рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд░рд┐рдореЛрдЯ рд╡реЗрдм рд╕рд░реНрд╡рд░ рдкрд░ рдЪрд▓рддрд╛ рд╣реИ, рддреЛ рдирд┐рджрд╛рди рдФрд░ рдбреАрдмрдЧрд┐рдВрдЧ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╕рд░реНрд╡рд░ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рдмрд┐рдирд╛ рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдЧреНрд░рд┐рдо рд░реВрдк рд╕реЗ рдзреНрдпрд╛рди рд░рдЦрдиреЗ рдпреЛрдЧреНрдп рд╣реИред
рдмрдЧ рдареАрдХ рдХрд░рдирд╛
рддреЛ, рдЪрд▓реЛ рдЕрдВрдд рдореЗрдВ рдмрдЧ рдХреЛ рдЙрд╕реА рдЙрдкрдирд╛рдо рд╕реЗ рдареАрдХ рдХрд░реЗрдВред
рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рджреЛ рд╕рдорд╕реНрдпрд╛ рдХреНрд╖реЗрддреНрд░ рд╣реИрдВ рдЬрд╣рд╛рдВ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдЪреЗрдХрд┐рдВрдЧ рдЧрд╛рдпрдм рд╣реИред рдкрд╣рд▓рд╛
after_login
рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд╣реИ, рдЬрд┐рд╕реЗ рддрдм рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд▓реЙрдЧ рдЗрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдореЗрдВ рдПрдХ рдирдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
if user is None: nickname = resp.nickname if nickname is None or nickname == "": nickname = resp.email.split('@')[0] nickname = User.make_unique_nickname(nickname) user = User(nickname = nickname, email = resp.email, role = ROLE_USER) db.session.add(user) db.session.commit()
рд╣рдорд╛рд░рд╛ рд╕рдорд╛рдзрд╛рди рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рдЙрдкрдирд╛рдо рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╡рд░реНрдЧ рдХреЛ рдирд┐рд░реНрджреЗрд╢ рджреЗрдирд╛ рд╣реИред рдЗрд╕реЗ рдЗрд╕реА рддрд░рд╣ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдлрд╝рд╛рдЗрд▓
app/models.py
) :
class User(db.Model): # ... @staticmethod def make_unique_nickname(nickname): if User.query.filter_by(nickname = nickname).first() == None: return nickname version = 2 while True: new_nickname = nickname + str(version) if User.query.filter_by(nickname = new_nickname).first() == None: break version += 1 return new_nickname # ...
рдпрд╣ рд╡рд┐рдзрд┐ рдХреЗрд╡рд▓ рддрдм рддрдХ рдЙрдкрдирд╛рдо рдореЗрдВ рдПрдХ рдХрд╛рдЙрдВрдЯрд░ рдЬреЛрдбрд╝рддреА рд╣реИ рдЬрдм рддрдХ рдХрд┐ рдпрд╣ рдЕрджреНрд╡рд┐рддреАрдп рди рд╣реЛ рдЬрд╛рдПред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ "рдорд┐рдЧреБрдПрд▓" рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рд╣реИ, рддреЛ рд╡рд┐рдХрд▓реНрдк "рдорд┐рдЧреБрдПрд▓ 2" рд╡рд┐рдзрд┐ рдореЗрдВ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдлрд┐рд░, рдЕрдЧрд░ рдРрд╕рд╛ рдХреЛрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣реИ, рддреЛ "рдорд┐рдЧреБрдПрд▓ 3" рдФрд░ рдЗрд╕реА рддрд░рд╣ред рд╕реНрдЯреЗрдЯрдорд┐рдереЛрдб рдбреЗрдХреЛрд░реЗрдЯрд░ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ , рд╣рдордиреЗ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдСрдкрд░реЗрд╢рди рд╡рд░реНрдЧ рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдмрдВрдзрд╛ рдирд╣реАрдВ рд╣реИред
рджреВрд╕рд░рд╛ рд╕реНрдерд╛рди рдЬрд╣рд╛рдВ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХреА рд╕рдорд╕реНрдпрд╛ рдЕрднреА рднреА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╣реИ рд╡рд╣ рд╣реИ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдПрдбрд┐рдЯрд┐рдВрдЧ рдкреЗрдЬред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕рдм рдХреБрдЫ рдЗрд╕ рддрдереНрдп рд╕реЗ рдЬрдЯрд┐рд▓ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдкрдиреЗ рдЙрдкрдирд╛рдо рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╕рдорд╛рдзрд╛рди рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рд╣реИ рдФрд░, рд╡рд┐рдлрд▓рддрд╛ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдПрдХ рдЕрдиреНрдп рдЙрдкрдирд╛рдо рдЪреБрдирдиреЗ рдХреА рдкреЗрд╢рдХрд╢ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХрд┐рд╕реА рдореМрдЬреВрджрд╛ рдЙрдкрдирд╛рдо рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдлрд╝реЙрд░реНрдо рдХреЗрд╡рд▓ рд╕рддреНрдпрд╛рдкрди рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдЕрдкрдиреЗ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ
validate
рд╡рд┐рдзрд┐ (
app/forms.py
) рдХреЛ рдУрд╡рд░рд▓реЛрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
from app.models import User class EditForm(Form): nickname = TextField('nickname', validators = [Required()]) about_me = TextAreaField('about_me', validators = [Length(min = 0, max = 140)]) def __init__(self, original_nickname, *args, **kwargs): Form.__init__(self, *args, **kwargs) self.original_nickname = original_nickname def validate(self): if not Form.validate(self): return False if self.nickname.data == self.original_nickname: return True user = User.query.filter_by(nickname = self.nickname.data).first() if user != None: self.nickname.errors.append('This nickname is already in use. Please choose another one.') return False return True
рдкреНрд░рдкрддреНрд░ рдирд┐рд░реНрдорд╛рддрд╛ рдЕрдм рдПрдХ рдирдпрд╛ рддрд░реНрдХ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ -
original_nickname
ред
validate
рд╡рд┐рдзрд┐ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ рдХрд┐ рдЙрдкрдирд╛рдо рдмрджрд▓ рдЧрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЕрдЧрд░ рдмрджрд▓рд╛ рд╣реИ, рддреЛ рд╣рдо рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП рдЬрд╛рдБрдЪ рдХрд░реЗрдВрдЧреЗред
рд╣рдо рдПрдХ рдирдП рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдлрд╝реЙрд░реНрдо рдХреЛ рдЖрд░рдВрдн рдХрд░рддреЗ рд╣реИрдВ:
@app.route('/edit', methods = ['GET', 'POST']) @login_required def edit(): form = EditForm(g.user.nickname) # ...
рд╣рдореЗрдВ рдЙрди рд╕рднреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рднреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдкреНрд░рдкрддреНрд░ рд╕рддреНрдпрд╛рдкрди рдХреЗ рджреМрд░рд╛рди рд╣реЛрддреА рд╣реИрдВ, рдЬрд┐рд╕ рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рддреНрд░реБрдЯрд┐ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЙрд╕рдХреЗ рдмрдЧрд▓ рдореЗрдВред (рдлрд╝рд╛рдЗрд▓
app/templates/edit.html
) :
<td>Your nickname:</td> <td> {{form.nickname(size = 24)}} {% for error in form.errors.nickname %} <br><span style="color: red;">[{{error}}]</span> {% endfor %} </td>
рдпрд╣ рд╕рдм, рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рд╣реЛ рдЧрдИ рд╣реИ! рдпрд╣ рд╕рдЪ рд╣реИ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдХрдИ рдереНрд░реЗрдбреНрд╕ рдпрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рддрдХ рдПрдХ рд╕рд╛рде рдкрд╣реБрдВрдЪрдиреЗ рдХреА рд╕рдВрднрд╛рд╡рд┐рдд рд╕рдорд╕реНрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд┐рд╖рдп рднрд╡рд┐рд╖реНрдп рдХреЗ рд▓реЗрдЦ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЕрдм рдЖрдк рдлрд┐рд░ рд╕реЗ рдЙрдкрдирд╛рдо рдХреЛ рдореМрдЬреВрджрд╛ рдПрдХ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреЛрдИ рдФрд░ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред
рдкрд░реАрдХреНрд╖рдг рд░реВрдкрд░реЗрдЦрд╛
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЗ рд╕рд╛рде, рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдирд╛ рдХрдард┐рди рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдХреЛрдб рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдореМрдЬреВрджрд╛ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдирд╣реАрдВ рддреЛрдбрд╝реЗрдВрдЧреЗред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдирд╛ рдЗрддрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред
рдкрд╛рд░рдВрдкрд░рд┐рдХ рдкрд░реАрдХреНрд╖рдг рджреГрд╖реНрдЯрд┐рдХреЛрдг рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИред рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦрддреЗ рд╣реИрдВред рд╕рдордп-рд╕рдордп рдкрд░ рд╡рд┐рдХрд╛рд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рджреМрд░рд╛рди, рдЖрдкрдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдХрд┐ рд╕рдм рдХреБрдЫ рдЕрднреА рднреА рд╕реНрдерд┐рд░ рд╣реИред рдкрд░реАрдХреНрд╖рдг рдХрд╡рд░реЗрдЬ рдЬрд┐рддрдирд╛ рд╡реНрдпрд╛рдкрдХ рд╣реЛрдЧрд╛, рдЙрддрдирд╛ рд╣реА рдЖрдк рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╕рдм рдХреБрдЫ рдХреНрд░рдо рдореЗрдВ рд╣реИред
рдЖрдЗрдП, рд╕рдмрд╕реЗ рдЫреЛрдЯреЗ рдореЙрдбреНрдпреВрд▓ (рдлрд╝рд╛рдЗрд▓
app/tests.py
) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдЫреЛрдЯрд╛ рдкрд░реАрдХреНрд╖рдг рдврд╛рдБрдЪрд╛ рд▓рд┐рдЦреЗрдВ:
#!flask/bin/python import os import unittest from config import basedir from app import app, db from app.models import User class TestCase(unittest.TestCase): def setUp(self): app.config['TESTING'] = True app.config['CSRF_ENABLED'] = False app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db') self.app = app.test_client() db.create_all() def tearDown(self): db.session.remove() db.drop_all() def test_avatar(self): u = User(nickname = 'john', email = 'john@example.com') avatar = u.avatar(128) expected = 'http://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6' assert avatar[0:len(expected)] == expected def test_make_unique_nickname(self): u = User(nickname = 'john', email = 'john@example.com') db.session.add(u) db.session.commit() nickname = User.make_unique_nickname('john') assert nickname != 'john' u = User(nickname = nickname, email = 'susan@example.com') db.session.add(u) db.session.commit() nickname2 = User.make_unique_nickname('john') assert nickname2 != 'john' assert nickname2 != nickname if __name__ == '__main__': unittest.main()
рдЗрд╕ рд▓реЗрдЦ рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рдкрд░реЗ
unittest
рдЪрд░реНрдЪрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдЗрд╕ рдореЙрдбреНрдпреВрд▓ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдЖрдк рдмрд╕ рдорд╛рди рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд░реАрдХреНрд╖рдг
TestCase
рдХреНрд▓рд╛рд╕ рдореЗрдВ рд╣реИрдВред
setUp
рдФрд░
tearDown
рд╡рд┐рд╢реЗрд╖ рдорд╣рддреНрд╡ рдХреЗ рд╣реИрдВ, рдЗрдиреНрд╣реЗрдВ рдХреНрд░рдорд╢рдГ рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рдФрд░ рдмрд╛рдж рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдХрдИ рдкрд░реАрдХреНрд╖рдг рд╕рдореВрд╣реЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд╣рд╛рдВ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣
unittest.TestCase
рдХрд╛ рдПрдХ рдЙрдкрд╡рд░реНрдЧ рд╣реИ, рдлрд┐рд░ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдХрд╛ рдЕрдкрдирд╛
setUp
рдФрд░
tearDown
ред
рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ рдФрд░ рдмрд╛рдж рдореЗрдВ рдХрд┐рд╕реА рднреА рдЬрдЯрд┐рд▓ рдХрд╛рд░реНрдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
setUp
, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдереЛрдбрд╝рд╛ рдмрджрд▓рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред
tearDown
рд╡рд┐рдзрд┐ рдореЗрдВ
tearDown
рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕рд╛рдл рдХрд░рддреЗ рд╣реИрдВред
рдкрд░реАрдХреНрд╖рдг рдЙрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рдХреБрдЫ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЗрд╕рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреА рддреБрд▓рдирд╛ рдЙрджреНрджреЗрд╢реНрдп рд╕реЗ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рдкрд░рд┐рдгрд╛рдо рдореЗрд▓ рдирд╣реАрдВ рдЦрд╛рддреЗ рд╣реИрдВ, рддреЛ рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдлрд▓ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдврд╛рдВрдЪреЗ рдореЗрдВ рджреЛ рдкрд░реАрдХреНрд╖рдг рд╣реИрдВред рдкрд╣рд▓реЗ рдЕрд╡рддрд╛рд░ URL рдХреА рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд┐рдЫрд▓реЗ рдЕрдзреНрдпрд╛рдп рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдерд╛ред рджреВрд╕рд░рд╛ рдкрд░реАрдХреНрд╖рдг
make_unique_nickname
рд╡рд┐рдзрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╣рдордиреЗ рдЕрднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╡рд░реНрдЧ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдерд╛ред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'рдЬреЙрди' рдирд╛рдо рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдкрд░реАрдХреНрд╖рдг рд╡рд┐рдзрд┐ рдХреЛ 'рдЬреЙрди' рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдПрдХ рдЙрдкрдирд╛рдо рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рдлрд┐рд░ рд╣рдо рд╕реБрдЭрд╛рдП рдЧрдП рдЙрдкрдирд╛рдо рдХреЗ рд╕рд╛рде рджреВрд╕рд░рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдмрдирд╛рддреЗ рдФрд░ рд╕рд╣реЗрдЬрддреЗ рд╣реИрдВ рдФрд░ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐
make_unique_nickname
рд▓рд┐рдП рдПрдХ рдФрд░ рдХреЙрд▓ рджреЛрдиреЛрдВ рдирд┐рд░реНрдорд┐рдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдирд╛рдореЛрдВ рд╕реЗ рдЕрд▓рдЧ рдирд╛рдо рд▓реМрдЯрд╛рдПрдЧрд╛ред
рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдБ:
./tests.py
рдпрджрд┐ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реЛрддреА рд╣реИ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдХрдВрд╕реЛрд▓ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЕрдВрддрд┐рдо рд╢рдмреНрдж
рдпрд╣ рдбрд┐рдмрдЧрд┐рдВрдЧ, рддреНрд░реБрдЯрд┐рдпреЛрдВ рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХреА рд╣рдорд╛рд░реА рдЪрд░реНрдЪрд╛ рдХрд╛ рд╕рдорд╛рдкрди рдХрд░рддрд╛ рд╣реИред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдпрд╣ рд▓реЗрдЦ рдЕрдЪреНрдЫрд╛ рд▓рдЧрд╛ рд╣реЛрдЧрд╛ред рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рдпрджрд┐ рдЖрдкрдХреЗ рдХреЛрдИ рдкреНрд░рд╢реНрди рд╣реИрдВ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдкреВрдЫреЗрдВред
рдирд╡реАрдирддрдо рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧрд┐рдВрдЧ рдХреЛрдб рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд▓рд┐рдВрдХ рдкрд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
рдорд╛рдЗрдХреНрд░реЛрдмреНрд▓реЙрдЧ-0.7.zip рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ
рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рдХреЛрдИ рдЖрднрд╛рд╕реА рд╡рд╛рддрд╛рд╡рд░рдг рдпрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдирд╣реАрдВ рд╣реИред рдЙрдирдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИред
рдЬрд▓реНрдж рдорд┐рд▓рддреЗ рд╣реИрдВ!
рдорд┐рдЧреБрдПрд▓