Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Solucionado (ver solução)

Bad Request quando tento atualizar o jogo sem mudar a imagem

Encontrei o mesmo problema que o do post https://cursos.alura.com.br/forum/topico-alteracao-do-jogo-73438, no qual o moderador respondeu que mais pra frente no curso isso seria explicado. Só que o curso termina, e o problema não é tratado.

Alguém saberia com consertar esse problema?

8 respostas

Oi Fernando, tudo bom? Vc consegue postar o seu código aqui para darmos uma olhada?

jogoteca

from flask import Flask
from flask_mysqldb import MySQL

app = Flask(__name__)
app.config.from_pyfile('config.py')

db = MySQL(app)

from views import *

if __name__ == '__main__':
    app.run(debug=True)

views.py

from flask import render_template, request, redirect, session, flash, url_for, send_from_directory
from models import Jogo
from dao import JogoDao, UsuarioDao
from jogoteca import db, app
import time
from helpers import recupera_imagem, deleta_arquivo

jogo_dao = JogoDao(db)
usuario_dao = UsuarioDao(db)


@app.route('/')
def index():
    lista = jogo_dao.listar()
    return render_template('lista.html', titulo='Jogos', jogos=lista)


@app.route('/novo')
def novo():
    if 'usuario_logado' not in session or session['usuario_logado'] is None:
        return redirect(url_for('login', proxima=url_for('novo')))
    return render_template('novo.html', titulo='Novo Jogo')


@app.route('/criar', methods=['POST', ])
def criar():
    nome = request. form['nome']
    categoria = request. form['categoria']
    console = request. form['console']
    jogo = Jogo(nome, categoria, console)
    jogo_dao.salvar(jogo)

    arquivo = request.files['arquivo']
    upload_path = app.config['UPLOAD_PATH']
    timestamp = time.time()
    arquivo.save(f'{upload_path}/capa{jogo.id}-{timestamp}.jpg')

    return redirect(url_for('index'))


@app.route('/login')
def login():
    proxima = request.args.get('proxima')
    return render_template('login.html', proxima=proxima)


@app.route('/autenticar', methods=['POST', ])
def autenticar():
    usuario = usuario_dao.buscar_por_id(request.form['usuario'])
    if usuario:
        if usuario.senha == request.form['senha']:
            session['usuario_logado'] = usuario.id
            flash(usuario.nome + ' logou com sucesso!')
            proxima_pagina = request.form['proxima']
            return redirect(proxima_pagina)
        else:
            flash('Senha incorreta, tente novamente!')
            return redirect(url_for('login'))
    else:
        flash('Não logado, tente novamente!')
        return redirect(url_for('login'))


@app.route('/logout')
def logout():
    session['usuario_logado'] = None
    flash('Nenhum usuário logado!')
    return redirect(url_for('index'))


@app.route('/editar/<int:id>')
def editar(id):
    if 'usuario_logado' not in session or session['usuario_logado'] is None:
        return redirect(url_for('login', proxima=url_for('editar', id=id)))
    jogo = jogo_dao.busca_por_id(id)
    nome_imagem = recupera_imagem(id)
    return render_template('editar.html', titulo='Editando Jogo', jogo=jogo, capa_jogo=nome_imagem)


@app.route('/atualizar', methods=['POST', ])
def atualizar():
    nome = request.form['nome']
    categoria = request.form['categoria']
    console = request.form['console']
    jogo = Jogo(nome, categoria, console, id=request.form['id'])

    arquivo = request.files['arquivo']
    upload_path = app.config['UPLOAD_PATH']
    timestamp = time.time()
    deleta_arquivo(jogo.id)
    arquivo.save(f'{upload_path}/capa{jogo.id}-{timestamp}.jpg')
    jogo_dao.salvar(jogo)

    return redirect(url_for('index'))


@app.route('/deletar/<int:id>')
def deletar(id):
    if 'usuario_logado' not in session or session['usuario_logado'] is None:
        return redirect(url_for('login', proxima=url_for('deletar', id=id)))
    jogo_dao.deletar(id)
    flash('O jogo foi removido com sucesso!')
    return redirect(url_for('index'))


@app.route('/uploads/<nome_arquivo>')
def imagem(nome_arquivo):
    return send_from_directory('uploads', nome_arquivo)

helpers.py

import os
from jogoteca import app


def recupera_imagem(id):
    conferencia = int(0)
    for nome_arquivo in os.listdir(app.config['UPLOAD_PATH']):
        if f'capa{id}' in nome_arquivo:
            conferencia += 1
            return nome_arquivo
    if conferencia == 0:
        return 'capa_padrao.jpg'


def deleta_arquivo(id):
    arquivo = recupera_imagem(id)
    os.remove(os.path.join(app.config['UPLOAD_PATH'], arquivo))

dao.py

from models import Jogo, Usuario

SQL_DELETA_JOGO = 'delete from jogo where id = %s'
SQL_JOGO_POR_ID = 'SELECT id, nome, categoria, console from jogo where id = %s'
SQL_USUARIO_POR_ID = 'SELECT id, nome, senha from usuario where id = %s'
SQL_ATUALIZA_JOGO = 'UPDATE jogo SET nome=%s, categoria=%s, console=%s where id = %s'
SQL_BUSCA_JOGOS = 'SELECT id, nome, categoria, console from jogo'
SQL_CRIA_JOGO = 'INSERT into jogo (nome, categoria, console) values (%s, %s, %s)'


class JogoDao:
    def __init__(self, db):
        self.__db = db

    def salvar(self, jogo):
        cursor = self.__db.connection.cursor()

        if jogo.id:
            cursor.execute(SQL_ATUALIZA_JOGO, (jogo.nome, jogo.categoria, jogo.console, jogo.id))
        else:
            cursor.execute(SQL_CRIA_JOGO, (jogo.nome, jogo.categoria, jogo.console))
            jogo.id = cursor.lastrowid
        self.__db.connection.commit()
        return jogo

novo.html

{% extends "template.html" %}
{% block conteudo %}
    <form action="{{ url_for('criar') }}" method="post" enctype="multipart/form-data">
        <figure class="thumb col-md-4">
            <img class="img-responsive" src="{{ url_for('imagem', nome_arquivo='capa_padrao.jpg') }}">
            <figcaption>
                <label>
                    Mudar capa
                    <input type="file" name="arquivo" accept=".jpg">
                </label>
            </figcaption>
        </figure>
        <fieldset>
            <div class="form-group">
                <label for="nome">Nome</label>
                <input type="text" id="nome" name="nome" class="form-control">
            </div>
            <div class="form-group">
                <label for="categoria">Categoria</label>
                <input type="text" id="categoria" name="categoria" class="form-control">
            </div>
            <div class="form-group">
                <label for="console">Console</label>
                <input type="text" id="console" name="console" class="form-control">
            </div>
            <button type="submit" class="btn btn-primary btn-salvar">Salvar</button>
            <a class="btn btn-danger" href="{{ url_for('index') }}">Voltar</a>
        </fieldset>
    </form>
{% endblock %}

editar.html

{% extends "template.html" %}
{% block conteudo %}
    <form action="{{ url_for('atualizar') }}" method="post" enctype="multipart/form-data">
        <figure class="thumb col-md-4">
            <img class="img-responsive" src="{{ url_for('imagem', nome_arquivo=capa_jogo) }}">
            <figcaption>
                <label class="fileContainer">
                    Mudar capa
                    <input type="file" name="arquivo" accept=".jpg">
                </label>
            </figcaption>
        </figure>
        <fieldset>
            <input type="hidden" name="id" value="{{ jogo.id }}">
            <div class="form-group">
                <label for="nome">Nome</label>
                <input type="text" id="nome" name="nome" class="form-control" value="{{ jogo.nome }}">
            </div>
            <div class="form-group">
                <label for="categoria">Categoria</label>
                <input type="text" id="categoria" name="categoria" class="form-control" value="{{ jogo.categoria }}">
            </div>
            <div class="form-group">
                <label for="console">Console</label>
                <input type="text" id="console" name="console" class="form-control" value="{{ jogo.console }}">
            </div>
            <button type="submit" class="btn btn-primary btn-salvar">Salvar</button>
            <a class="btn btn-danger" href="{{ url_for('index') }}">Voltar</a>
        </fieldset>
    </form>
{% endblock %}

app.js

$('form input[type="file"]').change(event => {
  let arquivos = event.target.files;
  if (arquivos.length === 0) {
    console.log('sem imagem pra mostrar')
  } else {
      if(arquivos[0].type == 'image/jpeg') {
        $('img').remove();
        let imagem = $('<img class="img-responsive">');
        imagem.attr('src', window.URL.createObjectURL(arquivos[0]));
        $('figure').prepend(imagem);
      } else {
        alert('Formato não suportado')
      }
  }
});

O máximo que consegui fazer foi colocar uma verificação na

recupera_imagem

pra retornar a capa padrão, porque quando eu tentava editar um jogo que não tinha imagem também recebia bad request.

Talvez o problema esteja nessa parte:

<figure class="thumb col-md-4">
            <img class="img-responsive" src="{{ url_for('imagem', nome_arquivo=capa_jogo) }}">
            <figcaption>
                <label class="fileContainer">
                    Mudar capa
                    <input type="file" name="arquivo" accept=".jpg">
                </label>
            </figcaption>
        </figure>

Porque se eu não clicar no "Mudar capa" e selecionar um arquivo, o "arquivo" fica vázio.

solução

Olá Fernando, tudo certo?

Imagino que isso esteja acontecendo por conta do trecho: request.files['arquivo']. Como você não está enviando nenhum arquivo, não existe uma chave no dicionário com este nome. Talvez, utilizar o método get dos dicionários e devolver uma string vazia como valor padrão resolva o problema. O código ficaria parecido com este:

@app.route('/atualizar', methods=['POST', ])
def atualizar():
    nome = request.form['nome']
    categoria = request.form['categoria']
    console = request.form['console']
    jogo = Jogo(nome, categoria, console, id=request.form['id'])

    arquivo = request.files.get('arquivo', '')
    upload_path = app.config['UPLOAD_PATH']

    if arquivo is not '':    
        timestamp = time.time()
        deleta_arquivo(jogo.id)
        arquivo.save(f'{upload_path}/capa{jogo.id}-{timestamp}.jpg')
        jogo_dao.salvar(jogo)

    return redirect(url_for('index'))

Opa Yuri, tudo bem e aí?

Funcionou! Coloquei também no def criar() porque estava dando um problema parecido. Só tirei o jogo_dao.salvar(jogo) de dentro do if, porque ele só estava salvando as outras alterações se o 'arquivo' não estivesse vazio. Ficou assim:

if arquivo is not '':    
        timestamp = time.time()
        deleta_arquivo(jogo.id)
        arquivo.save(f'{upload_path}/capa{jogo.id}-{timestamp}.jpg')

 jogo_dao.salvar(jogo)

Valeu pela ajuda e paciência!