πŸπŸ“š Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π°Π½Π°Π»ΠΎΠ³ LiveLib.ru Π½Π° Flask. Π§Π°ΡΡ‚ΡŒ 2: CRUD, IntegrityError ΠΈ валидация WTForms

Π’ Π·Π°ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ части: Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Π½Π°Π±ΠΎΡ€ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ для создания, рСдактирования ΠΈ удалСния записСй; обСспСчиваСм автоматичСскоС сТатиС Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Ρ… ΠΎΠ±Π»ΠΎΠΆΠ΅ΠΊ Π΄ΠΎ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Pillow.

Π’Ρ€Π΅Ρ‚ΠΈΠΉ этап

Π’ Π·Π°ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ части Ρ‚ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»Π° ΠΌΡ‹ рассмотрим основныС аспСкты Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Ρ„ΠΎΡ€ΠΌΠ°ΠΌΠΈ WTForms, Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ CRUD ΠΈ напишСм Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для экспорта ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…. Код для ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΈ Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ этапов Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π΅ΡΡ‚ΡŒ здСсь.

Валидация Ρ„ΠΎΡ€ΠΌ WTForms

Для получСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ… со стороны Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π° Π² Flask-прилоТСниях ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Ρ„ΠΎΡ€ΠΌΡ‹ WTForms. Π­Ρ‚ΠΈ Ρ„ΠΎΡ€ΠΌΡ‹ Β«ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈΒ» ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΎΠΏΡ†ΠΈΠΈ для Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ Π²Π²Π΅Π΄Π΅Π½Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…. Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Ρ„ΠΎΡ€ΠΌ Π·Π° счСт макросов ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€ΠΎΠ² Ρ‚ΠΎΠΆΠ΅ Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠΈΡ… слоТностСй, ΠΊΠ°ΠΊ ΠΌΡ‹ это ΡƒΠ²ΠΈΠ΄ΠΈΠΌ ΠΏΠΎΠ·ΠΆΠ΅.

Для взаимодСйствия с ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π½Π°ΠΌ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ Π΄Π²Π΅ Ρ„ΠΎΡ€ΠΌΡ‹ – BookForm ΠΈ UpdateBook. ΠŸΠ΅Ρ€Π²Π°Ρ ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° созданиС Π½ΠΎΠ²ΠΎΠΉ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ, вторая – Π·Π° Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ записи. ОблоТки ΠΊΠ½ΠΈΠ³ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΊΠ°ΠΊ Π²ΠΎ врСмя создания ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ, Ρ‚Π°ΠΊ ΠΈ послС – Π² процСссС рСдактирования. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ использования Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€ΠΎΠ²:

  1. DataRequired – Π½Π΅ даст ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ„ΠΎΡ€ΠΌΡƒ, Ссли ΠΏΠΎΠ»Π΅ останСтся Π½Π΅Π·Π°ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌ.
  2. Length(min=5, max=100) – минимальная Π΄Π»ΠΈΠ½Π° строки Π² ΠΏΠΎΠ»Π΅ – 5 символов, максимальная – 100.
  3. FileAllowed(['jpg', 'png']) – Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΡΡ‚ΡŒ ΠΊ Ρ„ΠΎΡ€ΠΌΠ΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ изобраТСния .jpg ΠΈ .png.
  4. NumberRange(min=1, max=5)]) – обСспСчиваСт Π²Π²ΠΎΠ΄ ΠΎΡ†Π΅Π½ΠΊΠΈ для ΠΊΠ½ΠΈΠ³ΠΈ Π² Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π΅ ΠΎΡ‚ 1 Π΄ΠΎ 5 Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ.

ΠšΡ€ΠΎΠΌΠ΅ стандартных Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€ΠΎΠ², ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ:

/reader/forms.py
def validate_title(self, title):
    	title = Book.query.filter_by(title=title.data).first()
    	if title:
            raise ValidationError('Вакая ΠΊΠ½ΠΈΠ³Π° ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π² спискС ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Ρ….')

Π­Ρ‚ΠΎΡ‚ Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€ ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ созданиС ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ с Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΊΠ½ΠΈΠ³ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π² Π±Π°Π·Π΅. Π‘Π΅Π· Π½Π΅Π³ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ остановится с ошибкой:

НазваниС ΠΊΠ½ΠΈΠ³ΠΈ оказалось Π½Π΅ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌ

Π­Ρ‚Π° ошибка связана с Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠΌ unique=True столбца title ΠΈ Π΅Π΅ ΠΏΡ€ΠΎΡ‰Π΅ ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Π΅ΠΌ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ. Но ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΌΡ‹ Ρ‚ΠΎΠΆΠ΅ рассмотрим Π½ΠΈΠΆΠ΅ – ΠΎΠ½Π° Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прСдставлСния.

Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста»

Π¨Π°Π±Π»ΠΎΠ½Ρ‹ для Ρ„ΠΎΡ€ΠΌ

Π€ΠΎΡ€ΠΌΠ°ΠΌ для создания ΠΈ рСдактирования записСй Π½ΡƒΠΆΠ½Ρ‹ ΡˆΠ°Π±Π»ΠΎΠ½Ρ‹. Π—Π΄Π΅ΡΡŒ Π΅ΡΡ‚ΡŒ ΠΊΠΎΠ΄ для create.html ΠΈ edit.html. Π¨Π°Π±Π»ΠΎΠ½ create.html прСдусматриваСт Π²Ρ‹Π²ΠΎΠ΄ ошибок:

create.htmlΒ 
{% if form.genre.errors %}
 {% for error in form.genre.errors %}
   <span class="text-danger">{{ error }}</span></br>
 {% endfor %}
{% endif %}

Для Π²Π²ΠΎΠ΄Π° ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ классы:

  • class="form-control-label" – однострочноС тСкстовоС ΠΏΠΎΠ»Π΅;
  • class="form-control-textarea" – многострочноС тСкстовоС ΠΏΠΎΠ»Π΅;
  • class="form-control-number" – Π²Π²ΠΎΠ΄ Ρ†ΠΈΡ„Ρ€;
  • class="form-control-file" – Π²Ρ‹Π±ΠΎΡ€ Ρ„Π°ΠΉΠ»Π°.

Π’ шаблонС edit.html ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Ρ„ΠΎΡ€ΠΌΡ‹, ΡƒΠΆΠ΅ внСсСнной Π² ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΡƒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ, – Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ Π±Ρ‹Π»ΠΎ ΠΏΡ€ΠΎΡ‰Π΅ Π΅Π΅ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. Π­Ρ‚Ρƒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ отправляСт Π² Ρ„ΠΎΡ€ΠΌΡƒ функция edit, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ рассмотрим Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠ·ΠΆΠ΅. Для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ шаблона Π½ΡƒΠΆΠ΅Π½ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ макрос – ΠΎΠ½ находится Π² Ρ„Π°ΠΉΠ»Π΅ formhelpers.html. Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Π² ΠΏΠ°ΠΏΠΊΡƒ /templates вмСстС с ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΌΠΈ шаблонами. Π’ шаблонС для рСдактирования Π΅ΡΡ‚ΡŒ Π±Π»ΠΎΠΊ для Π²Ρ‹Π²ΠΎΠ΄Π° сообщСний ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ… Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΡ‹Ρ… ΠΎΡ‚ Flask ΠΈ SQLAlchemy (ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ошибки Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ WTForms):

edit.htmlΒ 
{% with messages = get_flashed_messages() %}
  {% if messages %}
	{% for message in messages %}
  	<span class="text-danger">{{ message }}</span>
	{% endfor %}
  {% endif %}
{% endwith %}

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: для создания ΠΈ рСдактирования записСй ΠΏΡ€ΠΈ ΠΆΠ΅Π»Π°Π½ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ шаблон. Если Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π² шаблон edit.html ΠΊΠΎΠ΄ ΠΈΠ· create.html, ΠΎΠ½ Ρ‚ΠΎΡ‡Π½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ прСдставлСния. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, часто для рСдактирования ΠΈ создания записСй ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΊΠΎΠ΄ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈ Ρ‚ΠΎΠΌ ΠΆΠ΅ Ρ„Π°ΠΉΠ»Π΅. Π’ Π΄Π°Π½Π½ΠΎΠΌ случаС ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ Ρ„ΠΎΡ€ΠΌΡ‹ рСдактирования с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ макроса ΠΈΠ· _formhelpers.html просто Π² ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… цСлях.

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· Ρ„ΠΎΡ€ΠΌ

Для создания, рСдактирования ΠΈ удалСния записСй Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² Ρ„Π°ΠΉΠ»Π΅ routes.py. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для бСзопасной Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ. НачнСм с ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° Ρ„ΠΎΡ€ΠΌ ΠΈ модуля Pillow, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ обСспСчит автоматичСскоС сТатиС ΠΎΠ±Π»ΠΎΠΆΠ΅ΠΊ ΠΈ сохранСниС Ρ„Π°ΠΉΠ»ΠΎΠ² Π² Π½ΡƒΠΆΠ½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ uploads:

routes.py
from reader.forms import BookForm, UpdateBook
from PIL import Image

Ѐласку Ρ‚ΠΎΠΆΠ΅ потрСбуСтся ΠΈΠΌΠΏΠΎΡ€Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ – flash, url_for ΠΈ redirect. Pillow Π½ΡƒΠΆΠ½Ρ‹ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ os ΠΈ secrets, Π° для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибок Π±Π°Π·Ρ‹ понадобится IntegrityError.

Ѐункция для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΈ сохранСния ΠΎΠ±Π»ΠΎΠΆΠ΅ΠΊ ΠΊΠ½ΠΈΠ³ выглядит Ρ‚Π°ΠΊ:

routes.py
def save_picture(cover):
	random_hex = secrets.token_hex(8)
	_, f_ext = os.path.splitext(cover.filename)
	picture_fn = random_hex + f_ext
	picture_path = os.path.join(app.root_path, app.config['UPLOAD_FOLDER'], picture_fn)
	output_size = (220, 340)
	i = Image.open(cover)
	i.thumbnail(output_size)
	i.save(picture_path)
 	return picture_fn

Ѐункция создания Π½ΠΎΠ²Ρ‹Ρ… записСй выглядит Ρ‚Π°ΠΊ:

routes.py
@app.route('/create/', methods=('GET', 'POST'))
def create():
    form = BookForm()
    if form.validate_on_submit():
        if form.cover.data:
            cover = save_picture(form.cover.data)
        else:
            cover ='default.jpg'   
        title = form.title.data
        author = form.author.data
        genre = form.genre.data
        rating = int(form.rating.data)
        description = form.description.data
        notes = form.notes.data
        book = Book(title=title,
            author=author,
            genre=genre,
            rating=rating,
            cover=cover,
            description=description,
            notes=notes)
        db.session.add(book)
        db.session.commit()
        return redirect(url_for('index'))

    return render_template('create.html', form=form)

Если Π²ΠΎ врСмя создания Π½ΠΎΠ²ΠΎΠΉ записи ΠΎΠ±Π»ΠΎΠΆΠΊΠ° Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π°, Π² ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Как Π²ΠΈΠ΄Π½ΠΎ ΠΏΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌΡƒ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄Ρƒ, Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… сохраняСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ имя Ρ„Π°ΠΉΠ»Π° изобраТСния, сами ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚ΡΡ Π² ΠΏΠ°ΠΏΠΊΡƒ uploads.

Ѐункция для рСдактирования отправляСт Π² Ρ„ΠΎΡ€ΠΌΡƒ ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ Π² ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ„ΠΎΡ€ΠΌΠ° Π½Π΅ Π±Ρ‹Π»Π° пустой, ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ IntegrityError– ΠΎΠ½Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚, Ссли Π² процСссС рСдактирования ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π²Π²ΠΎΠ΄ΠΈΡ‚ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠ½ΠΈΠ³ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π² Π±Π°Π·Π΅:

routes.py
@app.route('/<int:book_id>/edit/', methods=('GET', 'POST'))
def edit(book_id):
    book = Book.query.get_or_404(book_id)
    form = UpdateBook()
    if form.validate_on_submit():
        if form.cover.data:
            cover = save_picture(form.cover.data)
        else:
            cover = book.cover
        book.title = form.title.data
        book.author = form.author.data
        book.genre = form.genre.data
        book.rating = int(form.rating.data)
        book.description = form.description.data
        book.notes = form.notes.data
        try:
            db.session.commit()
            return redirect(url_for('index'))
        except IntegrityError:
            db.session.rollback()
            flash('ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка: такая ΠΊΠ½ΠΈΠ³Π° ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π² Π±Π°Π·Π΅', 'error')
            return render_template('edit.html', form=form)

Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΡƒ ΠΊΠ½ΠΈΠ³ΠΈ ΠΏΡ€ΠΎΡ‰Π΅ простого:

routes.py
@app.post('/<int:book_id>/delete/')
def delete(book_id):
	book = Book.query.get_or_404(book_id)
	db.session.delete(book)
	db.session.commit()
	return redirect(url_for('index')) 

Для подтвСрТдСния удалСния ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π²ΡΠΏΠ»Ρ‹Π²Π°ΡŽΡ‰Π΅Π΅ ΠΎΠΊΠ½ΠΎ – ΠΊΠΎΠ΄ для этого ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π² ΡˆΠ°Π±Π»ΠΎΠ½Π°Ρ…. ΠžΡΡ‚Π°Π»ΠΎΡΡŒ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² base.html, index.html, book.html, best.html ΠΈ thrillers.html ссылки Π½Π° ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠΎ созданию, Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΡŽ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡Π΅ΠΊ:

{{ url_for('create') }}
{{ url_for('edit', book_id=book.id) }}
{{ url_for('delete', book_id=book.id) }}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ:

УдаляСм ДостоСвского

Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ:

Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠ΅ΠΌ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ

И ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ:

Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΡƒΡŽ запись

Экспорт Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· Π±Π°Π·Ρ‹

Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΈΠ· Π½Π°ΠΏΠΎΠ»Π½Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ самыми Ρ€Π°Π·Π½Ρ‹ΠΌΠΈ способами. ΠœΡ‹ рассмотрим простой ΠΈ ΠΏΡ€Π°ΠΊΡ‚ΠΈΡ‡Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ установки Π½ΠΈΠΊΠ°ΠΊΠΈΡ… Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ. Π€Π°ΠΉΠ» json, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ использовали Π² ΠΏΠ΅Ρ€Π²ΠΎΠΉ части Ρ‚ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»Π°, Π±Ρ‹Π» создан ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚Π°ΠΊΠΈΠΌ способом.

Для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Π½ΡƒΠΆΠ½ΠΎ внСсти нСбольшоС Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ» ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ /reader/models.py ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для /reader/routes.py. Π‘Π½Π°Ρ‡Π°Π»Π° Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΠΌ класс Book:

/reader/models.pyΒ 
from dataclasses import dataclass
@dataclass
class Book(db.Model):
	id: int
	title: str
	author: str
	genre: str
	cover: str
	rating: int
	description: str
	notes: str
	created_at: str

Π­Ρ‚ΠΈ Π΄Π°Π½Π½Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ экспортированы. Если Π½Π΅ Π½ΡƒΠΆΠ΅Π½ ID записи, ΠΈΠ»ΠΈ врСмя создания, ΠΈΠ»ΠΈ Π΅Ρ‰Π΅ Ρ‡Ρ‚ΠΎ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ – ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ строки ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ.

Π”ΠΎΠ±Π°Π²ΠΈΠΌ ΠΈΠΌΠΏΠΎΡ€Ρ‚ jsonify ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ экспорта Π² /reader/routes.py:

/reader/routes.py
@app.route('/export/')
def data():
  data = Book.query.all()
  return jsonify(data) 

Π’ Ρ„Π°ΠΉΠ» __init__.py Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ app.config['JSON_AS_ASCII'] = False – ΠΈΠ½Π°Ρ‡Π΅ jsonify вмСсто ΠΊΠΈΡ€ΠΈΠ»Π»ΠΈΡ†Ρ‹ экспортируСт Π°Π±Ρ€Π°ΠΊΠ°Π΄Π°Π±Ρ€Ρƒ.

ВсС Π³ΠΎΡ‚ΠΎΠ²ΠΎ: Ссли ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΏΠΎ адрСсу http://localhost:8000/export/, ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС содСрТимоС Π±Π°Π·Ρ‹ Π² Π²ΠΈΠ΄Π΅ словаря:

Π”Π°Π½Π½Ρ‹Π΅ экспортированы

На этом Ρ€Π°Π±ΠΎΡ‚Π° Π½Π°Π΄ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½Π°. ΠžΡ‡Π΅Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ SQLAlchemy Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ упростила процСсс Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. И хотя SQLAlchemy – Π½Π΅ СдинствСнная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π°Ρ Flask-прилоТСниям всС прСимущСства ORM, Π΅Π΅ ΡƒΠ²Π΅Ρ€Π΅Π½Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°Π·Π²Π°Ρ‚ΡŒ самой понятной ΠΈ Π³ΠΈΠ±ΠΊΠΎΠΉ, Ρ‡Π΅ΠΌ ΠΈ ΠΎΠ±ΡŠΡΡΠ½ΡΠ΅Ρ‚ΡΡ Π΅Π΅ ΠΏΠΎΠΏΡƒΠ»ΡΡ€Π½ΠΎΡΡ‚ΡŒ. НапоминаСм, Ρ‡Ρ‚ΠΎ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½Π°Ρ вСрсия ΠΊΠΎΠ΄Π° находится здСсь.

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
11 дСкабря 2018

ООП Π½Π° Python: ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python допускаСт Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ, Π½ΠΎ Π² Π΅Π³ΠΎ основС...
admin
28 июня 2018

3 самых Π²Π°ΠΆΠ½Ρ‹Ρ… сфСры примСнСния Python: возмоТности языка

БущСствуСт мноТСство областСй примСнСния Python, Π½ΠΎ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠ½ особСнно...
admin
13 фСвраля 2017

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python: ΠΎΡ‚ Π½ΠΎΠ²ΠΈΡ‡ΠΊΠ° Π΄ΠΎ профСссионала

Пошаговая инструкция для всСх, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒΒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python...