Added Attachment model

This commit is contained in:
Felipe Martín 2016-03-21 21:54:17 +01:00
parent 11e5412de6
commit acb4e22739
4 changed files with 167 additions and 1 deletions

View File

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Entry, Tag
from .models import Entry, Tag, Attachment
from ckeditor.widgets import CKEditorWidget
from django.utils.translation import ugettext as _
from reversion.admin import VersionAdmin
@ -15,6 +15,7 @@ class EntryAdminForm(forms.ModelForm):
model = Entry
fields = ('title', 'slug', 'draft', 'date', 'tags', 'content')
#
# ENTRY
#
@ -80,3 +81,12 @@ class TagAdmin(VersionAdmin):
pass
admin.site.register(Tag, TagAdmin)
#
# ATTACHMENT
#
class AttachmentAdmin(VersionAdmin):
pass
admin.site.register(Attachment, AttachmentAdmin)

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-21 19:29
from __future__ import unicode_literals
from django.db import migrations, models
import fmartingrcom.apps.blog.models
class Migration(migrations.Migration):
dependencies = [
('blog', '0002_auto_20160313_1051'),
]
operations = [
migrations.CreateModel(
name='Attachment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('filename', models.CharField(max_length=256)),
('sha1', models.CharField(max_length=40)),
('mimetype', models.CharField(blank=True, max_length=256, null=True)),
('file', models.FileField(upload_to=fmartingrcom.apps.blog.models.attachment_upload_to)),
('creation_date', models.DateTimeField(auto_now_add=True)),
('modification_date', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'Attachment',
},
),
]

View File

@ -1,12 +1,26 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import logging
import mimetypes
import os
import re
import shutil
import subprocess
from django.db import models
from django.conf import settings
from django.core.files import File
from django.utils.timezone import utc
from django.core.urlresolvers import reverse
from django.dispatch.dispatcher import receiver
from django.db.models.signals import pre_delete
from fmartingrcom.utils import sha1_checksum
import mistune
logger = logging.getLogger()
#
# ENTRY
@ -76,3 +90,106 @@ class Tag(models.Model):
class Meta:
app_label = 'blog'
ordering = ['name']
#
# ATTACHMENT
#
def attachment_upload_to(instance, filename):
return os.path.join('{}_.{}'.format(
instance.media_path, instance.extension
))
class Attachment(models.Model):
filename = models.CharField(max_length=256)
sha1 = models.CharField(max_length=40)
mimetype = models.CharField(max_length=256, blank=True, null=True)
file = models.FileField(upload_to=attachment_upload_to)
creation_date = models.DateTimeField(auto_now_add=True)
modification_date = models.DateTimeField(auto_now=True)
@property
def extension(self):
return self.file.url.split('.')[-1]
@property
def url(self):
return self.file.url
@property
def media_path(self):
p1 = self.sha1[0:2]
p2 = self.sha1[2:4]
return 'attachment/{}/{}/{}/'.format(p1, p2, self.sha1)
@staticmethod
def upload_file(handler, filename=None):
"""
Given a certain file handler returns an `Image` objects
handler can be:
+ django.core.files.File instance __or subclass of__ (UploadedFile)
+ string with an absolute path to an image
"""
FLAGS = 'rw+'
# File Path
if isinstance(handler, str):
f = File(open(handler, FLAGS))
elif issubclass(handler.__class__, File) or isinstance(handler, File):
# Re-read with correct flags
f = handler
f.mode = FLAGS
else:
# I give up!
f = handler
if not filename:
filename = f.name.split('/')[-1]
sha1 = sha1_checksum(f)
# Check if file exists
try:
obj = Attachment.objects.get(sha1=sha1)
except Attachment.DoesNotExist:
obj = Attachment()
obj.file = f
obj.sha1 = sha1
obj.filename = filename
obj.mimetype = Attachment.get_mimetype(f, obj.filename)
obj.save()
return obj
@staticmethod
def get_mimetype(handler, filename):
re_mime_validate = re.compile('\w+/\w+(; \w+=[^;]+)*')
# subprocess
p = subprocess.Popen(('file', '--brief', '--mime-type', '-'),
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = p.communicate(handler.read())
if re_mime_validate.match(stdout):
mimetype = stdout.split()[0]
else:
# by python
mime, encoding = mimetypes.guess_type(filename)
mimetype = mime if mime else None
# rewind file descriptor
handler.file.seek(0)
return mimetype
class Meta:
verbose_name = 'Attachment'
@receiver(pre_delete, sender=Attachment)
def clean_files_on_delete(sender, instance, **kwargs):
try:
shutil.rmtree('/'.join(instance.file.path.split('/')[:-1]))
except Exception as error:
logger.warning(error, exc_info=True)

8
fmartingrcom/utils.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
import hashlib
def sha1_checksum(handler):
f = open(handler.file.name, 'rb')
checksum = hashlib.sha1(f.read())
return checksum.hexdigest()