Added Attachment model
This commit is contained in:
parent
11e5412de6
commit
acb4e22739
|
@ -1,5 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Entry, Tag
|
from .models import Entry, Tag, Attachment
|
||||||
from ckeditor.widgets import CKEditorWidget
|
from ckeditor.widgets import CKEditorWidget
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from reversion.admin import VersionAdmin
|
from reversion.admin import VersionAdmin
|
||||||
|
@ -15,6 +15,7 @@ class EntryAdminForm(forms.ModelForm):
|
||||||
model = Entry
|
model = Entry
|
||||||
fields = ('title', 'slug', 'draft', 'date', 'tags', 'content')
|
fields = ('title', 'slug', 'draft', 'date', 'tags', 'content')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ENTRY
|
# ENTRY
|
||||||
#
|
#
|
||||||
|
@ -80,3 +81,12 @@ class TagAdmin(VersionAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
admin.site.register(Tag, TagAdmin)
|
admin.site.register(Tag, TagAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# ATTACHMENT
|
||||||
|
#
|
||||||
|
class AttachmentAdmin(VersionAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
admin.site.register(Attachment, AttachmentAdmin)
|
||||||
|
|
|
@ -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',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,12 +1,26 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import logging
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.files import File
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
from django.core.urlresolvers import reverse
|
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
|
import mistune
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ENTRY
|
# ENTRY
|
||||||
|
@ -76,3 +90,106 @@ class Tag(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'blog'
|
app_label = 'blog'
|
||||||
ordering = ['name']
|
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)
|
||||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue