Search code examples
pythondjangoformsfilefield

FileField not working in Django


I am trying to create FileField in my forms and without saving file locally, add the file(as an attachment) to email and send it. Email part of code works fine, but when i add FileField it shows me error "'str' object has no attribute 'get'" and i am struggling to figure out what is the problem.

view:

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)

form:

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:"

here is HTML code snippet, where i call for the form:

<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>

Environment:

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']

And that's the error i'm getting:

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'

After removing try-except case from views, i m getting following traceback: 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: 

Any help would be very much appreciated. Thanks!


Solution

  • It looks like the clickjacking middleware is blowing up because the response its reading is a string when it should be something else.

    Looking at your code this line might be the culprit return "Attachment error"

    try changing it to

    return HttpResponse('Attachment error')

    you can import HttpResponse like this from django.http import HttpResponse