Remove filehash, set pk to name (#33)

* Remove filehash, set pk to name

* remove stale comment and dead block
This commit is contained in:
Tyrel Souza 2017-01-27 15:52:02 -05:00 committed by GitHub
parent 4d29d41b07
commit 5b91a7b362
6 changed files with 74 additions and 48 deletions

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-27 20:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dbfilestorage', '0004_dbfile_mtime'),
]
operations = [
migrations.AlterField(
model_name='dbfile',
name='filehash',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='dbfile',
name='name',
field=models.CharField(max_length=100, primary_key=True, serialize=False),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-27 20:42
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('dbfilestorage', '0005_auto_20170127_2037'),
]
operations = [
migrations.RemoveField(
model_name='dbfile',
name='filehash',
),
]

View File

@ -7,8 +7,7 @@ class DBFile(models.Model):
# This is kept as `name` and not something like `md5` because the file # This is kept as `name` and not something like `md5` because the file
# operations pass around `name` as the identifier, so it's kept the same # operations pass around `name` as the identifier, so it's kept the same
# to make sense. # to make sense.
name = models.CharField(max_length=100) name = models.CharField(max_length=100, primary_key=True)
filehash = models.CharField(max_length=32, primary_key=True)
# file data # file data
content_type = models.CharField(max_length=100) content_type = models.CharField(max_length=100)
@ -16,8 +15,8 @@ class DBFile(models.Model):
mtime = models.DateTimeField(auto_now=True) mtime = models.DateTimeField(auto_now=True)
def __unicode__(self): def __unicode__(self):
return u"{filehash} <{content_type}>".format( return u"{name} <{content_type}>".format(
filehash=self.filehash, content_type=self.content_type) name=self.name, content_type=self.content_type)
def save(self, **kwargs): def save(self, **kwargs):
if self.content_type is None: if self.content_type is None:

View File

@ -1,6 +1,5 @@
import mimetypes import mimetypes
import logging import logging
import hashlib
import os import os
from django.db.transaction import atomic from django.db.transaction import atomic
@ -15,7 +14,7 @@ L = logging.getLogger(__name__)
def _get_object(param): def _get_object(param):
return DBFile.objects.filter(Q(name=param) | Q(filehash=param)).first() return DBFile.objects.filter(name=param).first()
class DBFileStorage(Storage): class DBFileStorage(Storage):
@ -55,21 +54,12 @@ class DBFileStorage(Storage):
# USE mimetypes.guess_type as an attempt at getting the content type. # USE mimetypes.guess_type as an attempt at getting the content type.
ct = mimetypes.guess_type(name)[0] ct = mimetypes.guess_type(name)[0]
# After we get the mimetype by name potentially, mangle it.
filehash = hashlib.md5(read_data).hexdigest()
file_ext = os.path.splitext(name)[1]
if not file_ext:
file_ext = ".txt"
# create the file, or just return name if the exact file already exists # create the file, or just return name if the exact file already exists
if not DBFile.objects.filter(filehash=filehash, name=name).exists(): if not DBFile.objects.filter(name=name).exists():
the_file = DBFile( the_file = DBFile.objects.create(
name=name, name=name,
filehash=filehash,
content_type=ct, content_type=ct,
b64=b64) b64=b64)
the_file.save()
return name return name
def get_available_name(self, name, max_length=None): def get_available_name(self, name, max_length=None):
@ -82,7 +72,7 @@ class DBFileStorage(Storage):
DBFile.objects.filter(pk=name).delete() DBFile.objects.filter(pk=name).delete()
def exists(self, name): def exists(self, name):
return DBFile.objects.filter(Q(name=name) | Q(filehash=name)).exists() return DBFile.objects.filter(name=name).exists()
def size(self, name): def size(self, name):
dbf = _get_object(name) dbf = _get_object(name)

View File

@ -13,12 +13,10 @@ def show_file(request, name):
:return HttpResponse: Rendered file :return HttpResponse: Rendered file
""" """
dbf = DBFile.objects.filter(Q(name=name)|Q(filehash=name)) dbf = get_object_or_404(DBFile, name=name)
if dbf.exists(): response = HttpResponse(
response = HttpResponse( dbf.b64.decode('base64'),
dbf[0].b64.decode('base64'), content_type=dbf.content_type)
content_type=dbf[0].content_type) response['Content-Disposition'] = 'attachment; filename="{}"'.format(
response['Content-Disposition'] = 'attachment; filename="{}"'.format( dbf.name)
dbf[0].name) return response
return response
raise Http404

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import hashlib
import os import os
from dbfilestorage.models import DBFile from dbfilestorage.models import DBFile
@ -21,7 +20,6 @@ class DBFileTest(TestCase):
def setUp(self): def setUp(self):
self.filename = "kris.jpg" self.filename = "kris.jpg"
self.filepath = os.path.join(PROJECT_ROOT, "test_files", self.filename) self.filepath = os.path.join(PROJECT_ROOT, "test_files", self.filename)
self.md5 = hashlib.md5(open(self.filepath, 'rb').read()).hexdigest()
self._upload() self._upload()
@ -31,16 +29,15 @@ class DBFileTest(TestCase):
def test_upload(self): def test_upload(self):
""" Test that the file storage uploads and puts in DB Properly """ """ Test that the file storage uploads and puts in DB Properly """
self.assertTrue(DBFile.objects.filter(filehash=self.md5).exists()) self.assertTrue(DBFile.objects.filter(name=self.filepath).exists())
def test_content_file(self): def test_content_file(self):
""" Test that this code works with ContentFile as well """ """ Test that this code works with ContentFile as well """
content_file = ContentFile(u"ΑΔΔGΕΝΕ") content_file = ContentFile(u"ΑΔΔGΕΝΕ")
content_file_md5 = hashlib.md5(u"ΑΔΔGΕΝΕ".encode('utf8')).hexdigest()
default_storage.save("unicode", content_file) default_storage.save("unicode", content_file)
unicode_file = DBFile.objects.get(filehash=content_file_md5) unicode_file = DBFile.objects.get(name="unicode")
self.assertEqual(unicode(unicode_file), self.assertEqual(unicode(unicode_file),
"{} <application/octet-stream>".format(content_file_md5)) "unicode <application/octet-stream>")
def test_no_duplicate_upload(self): def test_no_duplicate_upload(self):
""" Test that it won't make a new file if it already exists """ """ Test that it won't make a new file if it already exists """
@ -51,25 +48,25 @@ class DBFileTest(TestCase):
def test_equality(self): def test_equality(self):
""" Test that the DB entry matches what is expected from the file """ """ Test that the DB entry matches what is expected from the file """
with open(self.filepath, 'rb') as f: with open(self.filepath, 'rb') as f:
dbf = DBFile.objects.get(filehash=self.md5) dbf = DBFile.objects.get(name=self.filepath)
self.assertEqual(dbf.b64.decode("base64"), f.read()) self.assertEqual(dbf.b64.decode("base64"), f.read())
self.assertEqual(dbf.content_type, 'image/jpeg') self.assertEqual(dbf.content_type, 'image/jpeg')
def test_open(self): def test_open(self):
""" Test that the storage mechanism can upload """ """ Test that the storage mechanism can upload """
dbf = default_storage.open(self.md5) dbf = default_storage.open(self.filepath)
with open(self.filepath, 'rb') as f: with open(self.filepath, 'rb') as f:
self.assertEqual(dbf.read(), f.read()) self.assertEqual(dbf.read(), f.read())
def test_exists(self): def test_exists(self):
""" Test that the storage mechanism can check existance """ """ Test that the storage mechanism can check existance """
self.assertTrue(default_storage.exists(self.md5)) self.assertTrue(default_storage.exists(self.filepath))
def test_delete(self): def test_delete(self):
""" Test Deletion """ """ Test Deletion """
self.assertTrue(DBFile.objects.filter(filehash=self.md5).exists()) self.assertTrue(DBFile.objects.filter(name=self.filepath).exists())
default_storage.delete(self.md5) default_storage.delete(self.filepath)
self.assertFalse(DBFile.objects.filter(filehash=self.md5).exists()) self.assertFalse(DBFile.objects.filter(name=self.filepath).exists())
# Also test that calling delete on something that doesn't exist, # Also test that calling delete on something that doesn't exist,
# errors silently # errors silently
self.assertFalse(DBFile.objects.filter(name="Nothing").exists()) self.assertFalse(DBFile.objects.filter(name="Nothing").exists())
@ -77,20 +74,18 @@ class DBFileTest(TestCase):
def test_size(self): def test_size(self):
""" Ensure we can get the proper size """ """ Ensure we can get the proper size """
size = default_storage.size(self.md5) size = default_storage.size(self.filepath)
self.assertGreater(size, 0) self.assertGreater(size, 0)
def test_url(self): def test_url(self):
""" Test that the url returned is the md5 path not the filename """ """ Test that the url returned is the filename """
self.assertIn(self.filename, default_storage.url(self.md5)) self.assertIn(self.filename, default_storage.url(self.filename))
def test_view(self): def test_view(self):
client = Client() client = Client()
# check it works for both md5 and filename url = default_storage.url(self.filepath)
for param in (self.md5, self.filepath): resp = client.get(url)
url = default_storage.url(param) self.assertEqual(resp.status_code, 200)
resp = client.get(url)
self.assertEqual(resp.status_code, 200)
def test_view_fails(self): def test_view_fails(self):
client = Client() client = Client()
@ -107,7 +102,7 @@ class DBFileTest(TestCase):
client.login(username=my_admin.username, password='top_secret') client.login(username=my_admin.username, password='top_secret')
url = reverse("admin:dbfilestorage_dbfile_changelist") url = reverse("admin:dbfilestorage_dbfile_changelist")
resp = client.get(url) resp = client.get(url)
self.assertContains(resp, self.md5) self.assertContains(resp, self.filepath)
def test_mtime(self): def test_mtime(self):
""" Ensure we can get the modified time """ """ Ensure we can get the modified time """