FileField не работает в Django

Я пытаюсь создать FileField в своих формах и, не сохраняя файл локально, добавить файл (в виде вложения) в электронное письмо и отправить его. Часть кода электронной почты работает нормально, но когда я добавляю FileField, он показывает мне ошибку «объект 'str' не имеет атрибута 'get'», и я изо всех сил пытаюсь понять, в чем проблема.

Посмотреть:

def print(request):
    if request.method == 'POST':
        form = PrintForm(data=request.POST, request = request)
        #print(request.FILES)

        if form.is_valid():
            contact_name = request.POST.get('contact_name', '')
            contact_email = request.POST.get('contact_email', '')
            form_content = request.POST.get('content', '')
            supervisor = form.cleaned_data['supervisor']
            template = get_template('threeD/email/contact_template_for_printing.txt')
            context = Context({
                'contact_name': contact_name,
                'supervisor': supervisor,
                'contact_email': contact_email,
                'form_content': form_content,
            })
            content = template.render(context)
            subject = "New message"

            try:
                email = EmailMessage(
                    subject,
                    content,
                    contact_email,
                    [supervisor],
                    headers={'Reply-To': contact_email}
                )
                if request.FILES:
                    #uploaded_file = request.POST.get('file')

                    uploaded_file = request.FILES['stl_file']  # file is the name value which you have provided in form for file field
                    email.attach('uploaded_file.name, uploaded_file.read(), uploaded_file.content_type')
                email.send()
            except:
                return "Attachment error"

            messages.success(request, "Thank you for your message.")
            return redirect('/index/print/')

    else:
        form = PrintForm(request=request)

    context_dict = {}
    context_dict['printers'] = Printer.objects.all()
    context_dict['form'] = form
    return render(request, 'threeD/print.html', context_dict)

форма:

class PrintForm(forms.Form):
    contact_name = forms.CharField(required=True)
    contact_email = forms.EmailField(required=True)
    supervisor = forms.ChoiceField(
        choices=[(str(sup.email), str(sup.name)) for sup in Supervisors.objects.all()]
    )
    stl_file = forms.FileField(required=False)
    stl_file.help_text = "Upload your file as .STL format. If you have more than one file, " \
                     "make a .zip and upload them all at once"
    content = forms.CharField(
        required=True,
        widget=forms.Textarea
    )

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request")
        super(PrintForm, self).__init__(*args, **kwargs)
        self.fields['contact_name'].label = "Your name:"
        self.fields['stl_file'].label = "Choose your design file:"

вот фрагмент кода HTML, где я вызываю форму:

<div class="panel-body">
  <form role="form" action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {% load bootstrap %}
    {{ form|bootstrap }}          
    <div class="text-center">
      <button type="submit" class="btn btn-primary">
        <span class="glyphicon glyphicon-send"></span>
        Send a message
      </button>
    </div>
  </form>
</div>

Окружающая среда:

Request Method: POST
Request URL: http://localhost:8000/index/print/

Django Version: 1.9
Python Version: 3.4.3

Installed Applications:
['admin_tools',
 'admin_tools.theming',
 'admin_tools.menu',
 'admin_tools.dashboard',
 'threeD.apps.ThreedConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrapform',
 'django.contrib.sites',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'allauth.socialaccount.providers.facebook']

Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']

И это ошибка, которую я получаю:

Traceback:

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  235.                 response = middleware_method(request, response)

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\middleware\clickjacking.py" in process_response
  31.         if response.get('X-Frame-Options') is not None:

Exception Type: AttributeError at /index/print/
Exception Value: 'str' object has no attribute 'get'

После удаления try-except case из представлений я получаю следующую трассировку: Traceback:

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\handlers\base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "E:\Python\Facility\threeD\views.py" in print
  145.                 email.attach('uploaded_file.name, uploaded_file.read(), uploaded_file.content_type')

File "C:\Python34\lib\site-packages\django-1.9-py3.4.egg\django\core\mail\message.py" in attach
  307.             assert content is not None

Exception Type: AssertionError at /index/print/
Exception Value: 

Любая помощь будет очень высоко ценится. Спасибо!


person Ilja Leiko    schedule 18.04.2017    source источник


Ответы (2)


Похоже, что промежуточное программное обеспечение кликджекинга взрывается, потому что ответ, который он читает, представляет собой строку, хотя это должно быть что-то другое.

Глядя на ваш код, эта строка может быть виновником return "Attachment error"

попробуй изменить на

return HttpResponse('Attachment error')

вы можете импортировать HttpResponse следующим образом from django.http import HttpResponse

person davidejones    schedule 18.04.2017
comment
Спасибо за ваше сообщение, davidejones. Я попытался изменить код, чтобы вернуть HttpResponse («Ошибка вложения»), и когда я отправляю свою форму, она, по-видимому, попадает в мою попытку-за исключением и возвращает мне пустой экран с текстом Ошибка вложения - person Ilja Leiko; 18.04.2017
comment
Отлично, так что вы исправили немедленную ошибку, с которой вы столкнулись, теперь вы можете перейти к исправлению того, почему она попадает в попытку улова. Вы должны зарегистрировать/вывести ошибку в улове или полностью удалить улов попытки, чтобы вы могли видеть ошибку. - person davidejones; 18.04.2017
comment
Что ж, это хороший момент. Теперь я получаю сообщение об ошибке: AssertionError в /index/print/ (это мой шаблон, который я вызываю) Сообщение об исключении не предоставлено - person Ilja Leiko; 18.04.2017
comment
Я обновил вопрос с трассировкой моей текущей ошибки. Мне действительно кажется, что способ, которым я прикрепляю файл (из буфера), работает неправильно - person Ilja Leiko; 18.04.2017
comment
После удаления квадратных скобок из метода присоединения он успешно передает эти строки, но показывает ошибку в строке email.send(): для распаковки требуется более 1 значения. блин, я так запутался со всем этим - person Ilja Leiko; 18.04.2017
comment
Похоже, что строка прикрепления электронной почты не работает. Эти переменные не должны быть в кавычках, вот сигнатура метода def attach(self, filename=None, content=None, mimetype=None) - person davidejones; 18.04.2017
comment
вау, вы правы, проблема с линией подключения. Я изменил его на: email.attach(lala, uploaded_file.read()) для проверки, и электронное письмо было отправлено с прикрепленным файлом - это круто. Но я получил его как lala.dat (который случайно угадывается и присваивается расширение, как говорится в документации django). Но как мне сохранить загруженное имя файла и тип файла? :) - person Ilja Leiko; 18.04.2017
comment
Можете ли вы принять ответ на этот вопрос, поскольку вы создали дополнительный вопрос, чтобы справиться с вашими новыми ошибками. - person davidejones; 18.04.2017
comment
davidjones, как вы думаете, мне лучше удалить этот пост, так как он не помогает мне решить проблему, кроме как приблизить на один шаг к осознанию того, где возникает проблема? - person Ilja Leiko; 18.04.2017
comment
Технически я решил проблему с Exception Value: 'str' object has no attribute 'get', поэтому я думаю, что можно оставить вопрос, он может помочь другим. - person davidejones; 18.04.2017

Вы не должны использовать request.POST и request.FILES для заполнения модели/БД. Вы должны использовать данные из формы.

Итак, для поля файла вы должны сделать

uploaded_file = form.cleaned_data['stl_file'] 

Также не делайте этого, используйте данные из form.cleaned_data

contact_name = request.POST.get('contact_name', '')

Скорее используйте

contact_name = form.cleaned_data.get('contact_name', '')
person Rohan    schedule 18.04.2017
comment
Спасибо за комментарий, Рохан. Я пытался использовать uploaded_file = form.cleaned_data['stl_file'], но безуспешно. Он все еще взрывается и показывает мне ту же ошибку: / Я также пытался использовать подход contact_name = form.cleaned_data.get('contact_name', ''), но он показывает мне ошибку: объект 'dict' не вызывается - person Ilja Leiko; 18.04.2017