Python/Pyramid: Тази функция ще позволи ли на потребителите да качват файлове и след това да ги анализират?

В момента имам този формуляр:

<form action="/store_stl_data" method="post" accept-charset="utf-8"
      enctype="multipart/form-data">

    <label for="stl">STL</label>
    <input id="stl" name="stl" type="file" value="" />

    <input type="submit" value="submit" />
</form>

тогава в моя views.py имам

@view_config(route_name='store_stl_data', renderer='templates/edit')

def store_stl_data(request):
    input_file=request.POST['stl'].file
    i1, i2 = itertools.tee(input_file)
    vertices = [map(float, line.split()[1:4])
                for line in i1
                if line.lstrip().startswith('vertex')]

    normals = [map(float, line.split()[2:5])
                for line in i2
                if line.lstrip().startswith('facet')]

        ...(parsing data)...
    return data

Трите реда под def store_stl_data(request): са тези, за които най-много не съм сигурен. Взех ги от този урок.

Искам така, че когато хората качат файла, цялата функция store_stl_data да работи и да обработва входния файл.

Точно сега ми дава грешка:

KeyError: "No key 'stl': Not a form request"

Ето и моя маршрут, в __init__.py:

from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('view_wiki', '/')
    config.add_route('view_page', '/{pagename}')
    config.add_route('add_page', '/add_page/{pagename}')
    config.add_route('edit_page', '/{pagename}/edit_page')
    config.scan()
    return config.make_wsgi_app()

person BigBoy1337    schedule 17.01.2013    source източник
comment
изглежда добре за мен. пробвал ли си го   -  person Eevee    schedule 17.01.2013
comment
Ако имате кода, трябва лесно да видите какво прави и дали работи. Не забравяйте да пишете и тестове!   -  person Chris Morgan    schedule 17.01.2013
comment
input_file вече е отворен файлов обект. Не е необходимо да го отваряте отново.   -  person Martijn Pieters    schedule 17.01.2013
comment
Актуализирах кода и съобщението за грешка, което показва   -  person BigBoy1337    schedule 18.01.2013
comment
защо имаш store_stl_file и store_stl_data? има ли две функции или едната е името на маршрута към името на функцията?   -  person Jonathan Vanasco    schedule 19.01.2013
comment
опа. добро хващане. Актуализирах въпроса   -  person BigBoy1337    schedule 19.01.2013


Отговори (1)


Обектът .file, който получавате от заявката, вече е отворен обект (подобен на файл).

Ако разгледате внимателно примера в документацията, към която сте дали връзка, той създава нов файл, използвайки името на файла за качване, и използва качения файл, за да запише данни в този нов файл. input_file никога не се отваря в този код, само output_file е (обърнете внимание на различното име на променливата там).

Не е необходимо да затваряте и файловия обект, така че не е необходим with. Вашият код може да бъде опростен до:

def store_stl_data(request):
    input_file=request.POST['stl'].file
    i1, i2 = itertools.tee(input_file)
    vertices = [map(float, line.split()[1:4])
                for line in i1
                if line.lstrip().startswith('vertex')]

    normals = [map(float, line.split()[2:5])
                for line in i2
                if line.lstrip().startswith('facet')]

Аз лично не бих използвал itertools.tee за това обаче, вие четете целия файл в буфера tee, докато изграждате върхове.

Вместо това бих използвал единичен цикъл:

def store_stl_data(request):
    input_file=request.POST['stl'].file
    vertices, normals = [], []
    for line in input_file
        parts = line.split()
        if parts[0] == 'vertex':
            vertices.append(map(float, parts[1:4]))
        elif parts[0] == 'facet':
            normals.append(map(float, parts[2:5]))

Сега само един ред наведнъж се съхранява в паметта (плюс структурата на върховете и нормалите).

Забележка: Ако получите съобщение за грешка KeyError: No key '...': Not a form request, значи изгледът не е получил POST HTTP заявка. Проверете два пъти, че методът на формуляра ви е зададен на "POST" (регистрът няма значение).

person Martijn Pieters    schedule 17.01.2013
comment
Благодаря за бакшиша. Актуализирах въпроса и моя код с вашето решение, въпреки че сега ми дава грешка (вижте въпроса) - person BigBoy1337; 18.01.2013
comment
Качихте ли файл? Ключът „stl“ не присъства в публикацията. - person Martijn Pieters; 18.01.2013
comment
Не, актуализирах кода си в отговор на вашия отговор. Ключовата грешка, посочена в сега актуализирания въпрос, възниква, когато се опитам да изпратя формуляра - person BigBoy1337; 19.01.2013
comment
Добре, точната грешка означава, че не сте направили POST заявка. Сигурни ли сте, че сте настроили правилния маршрут/формуляр/манипулатор? - person Martijn Pieters; 19.01.2013
comment
Добавих маршрута (init.py) към моя въпрос. Що се отнася до формата и манипулатора, останах с впечатлението, че това са съответно функциите @view_config и def store_stl_data. Това не е ли вярно? - person BigBoy1337; 19.01.2013
comment
@BigBoy1337: Там няма нищо, което да ми казва защо не правите подходящ POST в изгледа. - person Martijn Pieters; 19.01.2013