diff --git a/.gitignore b/.gitignore
index f3d001706f..78b657e227 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@ var/
local_settings.py
*.sqlite3
**/migrations/*
+
+# Local media storage (only when running in development mode)
+InvenTree/media
\ No newline at end of file
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index 259d7c7a22..f348cdfe04 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -135,3 +135,8 @@ USE_TZ = True
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'
+
+MEDIA_URL = '/media/'
+
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+
diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py
index 0c9c5465eb..3e09f6e5ee 100644
--- a/InvenTree/InvenTree/urls.py
+++ b/InvenTree/InvenTree/urls.py
@@ -76,4 +76,11 @@ urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
-] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+]
+
+# Static file access
+urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+
+if settings.DEBUG:
+ # Media file access
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
\ No newline at end of file
diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py
index 6e8f12eeae..790cd28618 100644
--- a/InvenTree/part/models.py
+++ b/InvenTree/part/models.py
@@ -6,6 +6,8 @@ from django.core.validators import MinValueValidator
from InvenTree.models import InvenTreeTree
+import os
+
#from django.db.models.signals.pre_delete
#from django.dispatch import receiver
@@ -21,15 +23,24 @@ class PartCategory(InvenTreeTree):
def parts(self):
return self.part_set.all()
-"""
-@receiver(pre_delete, sender=PartCategory)
-def reset_tag(sender, **kwargs):
- cat = kwargs['instance']
- for book in books.filter(tag=tag):
- book.tag = book.author.tags.first()
- book.save()
-"""
+# Function to automatically rename a part image on upload
+# Format: part_pk.
+def rename_part_image(instance, filename):
+ base = 'part_images'
+
+ if filename.count('.') > 0:
+ ext = filename.split('.')[-1]
+ else:
+ ext = ''
+
+ fn = 'part_{pk}_img'.format(pk=instance.pk)
+
+ if ext:
+ fn += '.' + ext
+
+ return os.path.join(base, fn)
+
class Part(models.Model):
""" Represents an abstract part
@@ -54,6 +65,8 @@ class Part(models.Model):
null=True, blank=True,
on_delete=models.SET_NULL)
+ image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True)
+
# Minimum "allowed" stock level
minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)])
diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html
index 6f29e9fb4e..128c4e19f2 100644
--- a/InvenTree/part/templates/part/part_base.html
+++ b/InvenTree/part/templates/part/part_base.html
@@ -4,13 +4,26 @@
{% include "part/cat_link.html" with category=part.category %}
-{{ part.name }}
-
-
-{{ part.description }}
-
-IPN: {% if part.IPN %}{{ part.IPN }}{% else %}N/A{% endif %}
-
+
{{ part.description }}
+ {% endif %} + {% if part.IPN %} +IPN: {{ part.IPN }}
+ {% endif %} + {% if part.URL %} +{% include 'url.html' with url=part.URL %}
+ {% endif %} +