title: Upload image using Django built in forms
body: <p>I am trying to upload an image using the Django built in forms, and can't seem to get the image to actually be stored. The form functions as expected, where I can browse for a file, and submit the form (everything else from form is posted and saved), but the image does not get saved into the "media/images" folder</p>
  
  <p>What am I missing here?</p>
  
  <p><strong>models.py</strong></p>
  
  <pre><code>from django.db import models
  from django.conf import settings
  from django.contrib.auth.models import AbstractUser
  from django.db.models.signals import post_save
  from django.db.models.signals import pre_save
  from django.core.files.storage import FileSystemStorage
  
  class CustomUser(AbstractUser):
      customerTag = models.CharField(max_length=50,)
      deviceSerial= models.CharField(max_length=50,)
      image = models.ImageField(upload_to='images/', blank = True)
      #also tried: image = models.ImageField(upload_to='media/', blank = True)
  </code></pre>
  
  <p><strong>views.py</strong></p>
  
  <pre><code>from django.contrib.auth.forms import UserCreationForm
  from django.urls import reverse_lazy
  from django.views import generic
  from django.views.generic.edit import CreateView
  from . import models
  from .models import CustomUser
  from .forms import addNewEquipmentForm
  from django.core.files.storage import FileSystemStorage
  
  class addEquipment(generic.CreateView):
      form_class = addNewEquipmentForm
      success_url = reverse_lazy('login')
      template_name = 'add_equipment.html'
  </code></pre>
  
  <p><strong>forms.py</strong></p>
  
  <pre><code>from django import forms
  from django.contrib.auth.forms import UserCreationForm, UserChangeForm
  from .models import CustomUser
  
  class addNewEquipmentForm(UserCreationForm):
      class Meta(UserCreationForm.Meta):
          model = CustomUser
          fields = ('username', 'email', 'customerTag', 'deviceSerial','image', )
  </code></pre>
  
  <p><strong>urls.py</strong></p>
  
  <pre><code>from django.urls import path, include
  from . import views
  from django.conf.urls.static import static
  from django.conf import settings
  
  urlpatterns = [
      #path('', views.home),
      path('login/', include('django.contrib.auth.urls')),#django powered login page
      path('newequipment/',views.addEquipment.as_view(), name='newEquipment'),
  ] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
  </code></pre>
  
  <p><strong>settings.py</strong></p>
  
  <pre><code>STATIC_URL = '/static/'
  
  MEDIA_URL = '/media/'
  MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  
  STATICFILES_DIRS = [
      os.path.join(BASE_DIR, "static")
  ]
  
  STATIC_ROOT = os.path.join(BASE_DIR, "static_files")
  </code></pre>
  
  <p><strong>form - Generated by Django:</strong> Sorry about the formatting, I am quite the novice in HTML...</p>
  
  <pre><code>&lt;head&gt;
  
    &lt;meta charset="utf-8"&gt;
    &lt;meta name="viewport" content="width=device-width,
    initial-scale=1, shrink-to-fit=no"&gt;
  
    &lt;link rel="stylesheet" 
    href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/
    bootstrap.min.css" integrity="sha384-MCw98
    /SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" 
    crossorigin="anonymous"&gt;
  
  &lt;/head&gt;
  &lt;body&gt;
      &lt;nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4"&gt;
      &lt;a class="navbar-brand" href="/"&gt;PolySense Solutions&lt;/a&gt;
  
      &lt;ul class="navbar-nav mr-auto"&gt;
      &lt;/ul&gt;
  
  &lt;button class="navbar-toggler" type="button" data-toggle="collapse" \="" 
      data-target="#navbarCollapse" aria-controls="navbarCollapse" aria- 
      expanded="false" aria-label="Toggle navigation"&gt;
      &lt;span class="navbar-toggler-icon"&gt;&lt;/span&gt;
  &lt;/button&gt;
  &lt;button class="navbar-toggler" type="button" data-toggle="collapse" data- 
      target="#navbarCollapse" aria-controls="navbarCollapse" aria- 
      expanded="false" aria-label="Toggle navigation"&gt;
      &lt;span class="navbar-toggler-icon"&gt;&lt;/span&gt;
  &lt;/button&gt;
  &lt;div class="collapse navbar-collapse" id="navbarCollapse"&gt;
  
  &lt;ul class="navbar-nav ml-auto"&gt;
      &lt;li class="nav-item"&gt;
      &lt;a class="nav-link dropdown-toggle" href="#" id="userMenu" data- 
      toggle="dropdown" aria-haspopup="true" aria-expanded="false"&gt;
      admin
   &lt;/a&gt;
  &lt;div class="dropdown-menu dropdown-menu-right" aria-labelledby="userMenu"&gt;
  &lt;a class="dropdown-item" href="/accounts/login/password_change/"&gt;Change 
  password&lt;/a&gt;
  &lt;div class="dropdown-divider"&gt;&lt;/div&gt;
   &lt;a class="dropdown-item" href="/accounts/login/logout/"&gt;
  Log out&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;/ul&gt;
  &lt;/div&gt;
  &lt;/nav&gt;
  &lt;div class="container"&gt;
  &lt;div class="container"&gt;
  &lt;br&gt;
  &lt;form method="post"&gt;
  &lt;input type="hidden" name="csrfmiddlewaretoken" 
  value="Yi8mpT2rqDGs8ncI05ePMoi4QECBQLPZ3JTKGRbZi1z0VP5nyWPIo7jZvxurx9tA"&gt;
  &lt;div id="div_id_username" class="form-group"&gt; &lt;label for="id_username" 
  class="col-form-label  requiredField"&gt;
  Username&lt;span class="asteriskField"&gt;*&lt;/span&gt; &lt;/label&gt; &lt;div 
  class=""&gt; &lt;input type="text" name="username" maxlength="150" autofocus="" 
  class="textinput textInput form-control" required="" id="id_username"&gt; 
  &lt;small id="hint_id_username" class="form-text text-muted"&gt;Required. 150 
  characters or fewer. Letters, digits and @/./+/-/_ only.&lt;/small&gt; &lt;/div&gt; 
  &lt;/div&gt; &lt;div id="div_id_email" class="form-group"&gt; &lt;label for="id_email" 
  class="col-form-label "&gt;
              Email address
          &lt;/label&gt; &lt;div class=""&gt; &lt;input type="email" name="email" 
   maxlength="254" class="emailinput form-control" id="id_email"&gt; &lt;/div&gt; 
  &lt;/div&gt; 
  &lt;div id="div_id_customerTag" class="form-group"&gt; &lt;label 
  for="id_customerTag" 
  class="col-form-label  requiredField"&gt;
              CustomerTag&lt;span class="asteriskField"&gt;*&lt;/span&gt; &lt;/label&gt; &lt;div 
  class=""&gt; &lt;input type="text" name="customerTag" maxlength="50" 
  class="textinput textInput form-control" required="" id="id_customerTag"&gt; 
  &lt;/div&gt; &lt;/div&gt; &lt;div id="div_id_deviceSerial" class="form-group"&gt; &lt;label 
  for="id_deviceSerial" class="col-form-label  requiredField"&gt;
              DeviceSerial&lt;span class="asteriskField"&gt;*&lt;/span&gt; &lt;/label&gt; &lt;div 
  class=""&gt; &lt;input type="text" name="deviceSerial" maxlength="50" 
  class="textinput textInput form-control" required="" id="id_deviceSerial"&gt; 
  &lt;/div&gt; &lt;/div&gt; &lt;div id="div_id_equipment" class="form-group"&gt; &lt;label 
  for="id_equipment" class="col-form-label  requiredField"&gt;
  
  &lt;/select&gt; &lt;/div&gt; &lt;/div&gt; &lt;div id="div_id_image" class="form-group"&gt; &lt;label 
  for="id_image" class="col-form-label "&gt;
              Image
          &lt;/label&gt; &lt;div class=""&gt; &lt;input type="file" name="image" 
  accept="image/*" class="clearablefileinput" id="id_image"&gt; &lt;/div&gt; &lt;/div&gt; 
  &lt;div id="div_id_password1" class="form-group"&gt; &lt;label for="id_password1" 
  class="col-form-label  requiredField"&gt;
              Password&lt;span class="asteriskField"&gt;*&lt;/span&gt; &lt;/label&gt; &lt;div 
  class=""&gt; &lt;input type="password" name="password1" 
  class="textinput textInput 
  form-control" required="" id="id_password1"&gt; &lt;small id="hint_id_password1" 
  class="form-text text-muted"&gt;&lt;ul&gt;&lt;li&gt;Your password can't be too similar to 
  your other personal information.&lt;/li&gt;&lt;li&gt;Your 
  password must contain at least 
  8 characters.&lt;/li&gt;&lt;li&gt;Your password can't be a commonly used password. 
  &lt;/li&gt; 
  &lt;li&gt;Your password can't be entirely numeric.&lt;/li&gt;&lt;/ul&gt;&lt;/small&gt; &lt;/div&gt; 
  &lt;/div&gt; 
  &lt;div id="div_id_password2" class="form-group"&gt; &lt;label for="id_password2" 
  class="col-form-label  requiredField"&gt;
              Password confirmation&lt;span class="asteriskField"&gt;*&lt;/span&gt; 
  &lt;/label&gt; &lt;div class=""&gt; &lt;input type="password" name="password2" 
  class="textinput textInput form-control" required="" id="id_password2"&gt; 
  &lt;small id="hint_id_password2" class="form-text text-muted"&gt;Enter the same 
  password as before, for verification.&lt;/small&gt; &lt;/div&gt; &lt;/div&gt;
  
  &lt;button class="btn btn-success" type="submit"&gt;Sign up&lt;/button&gt;
  &lt;/form&gt;
  &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p></p>
  
  <p><strong>template used to generate form:</strong></p>
  
  <pre><code>{% extends 'base.html' %}
  {% load crispy_forms_tags %}
  
  &lt;title&gt;Create New Equipment&lt;/title&gt;
  
  {% block body %}
  &lt;div class="container"&gt;
    &lt;br&gt;
    &lt;form method="post"&gt;
    {% csrf_token %}
    {{ form|crispy }}
    &lt;button class="btn btn-success" type="submit"&gt;Sign up&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
  {% endblock %}
  </code></pre>