From aefdcd3935ba0e8ff4126585bc2022f87f6e8067 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Thu, 11 Oct 2018 15:33:18 +0800 Subject: [PATCH 1/9] fixes for python3 and django1.11 --- browse_and_upload_field/fields.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index 07e93e1..594870d 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -191,9 +191,9 @@ def upload_callback(self, sender, instance, **kwargs): new_path = os.path.split(new_file)[0] if not os.path.isdir(new_path): os.makedirs(new_path) - os.chmod(new_path, 0775) + os.chmod(new_path, 0o775) file_move_safe(os.path.join(settings.MEDIA_ROOT, field.path), new_file, allow_overwrite=False) - os.chmod(new_file, 0775) + os.chmod(new_file, 0o775) setattr(instance, self.name, new_file.replace(settings.MEDIA_ROOT + "/", "")) instance.save() @@ -202,7 +202,7 @@ def upload_callback(self, sender, instance, **kwargs): for v in settings.FILEBROWSER_VERSIONS: # Getattr again as the property has been changed version = getattr(instance, self.name).version_generate(v) - os.chmod(os.path.join(settings.MEDIA_ROOT, version.path), 0775) + os.chmod(os.path.join(settings.MEDIA_ROOT, version.path), 0o775) def contribute_to_class(self, cls, name): models.signals.post_save.connect(self.upload_callback, sender=cls) From 43f6a2acc64e4c3b7028e69e6dc457e0d085de39 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Thu, 11 Oct 2018 22:41:25 +0800 Subject: [PATCH 2/9] fixes for python3 and django1.11 --- browse_and_upload_field/fields.py | 51 ++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index 594870d..7331cb1 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -24,6 +24,55 @@ from filebrowser.sites import site +class SubfieldBase(type): + """ + A metaclass for custom Field subclasses. This ensures the model's attribute + has the descriptor protocol attached to it. + """ + def __new__(cls, name, bases, attrs): + + new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs) + new_class.contribute_to_class = make_contrib( + new_class, attrs.get('contribute_to_class') + ) + return new_class + + +class Creator(object): + """ + A placeholder class that provides a way to set the attribute on the model. + """ + def __init__(self, field): + self.field = field + + def __get__(self, obj, type=None): + if obj is None: + return self + return obj.__dict__[self.field.name] + + def __set__(self, obj, value): + obj.__dict__[self.field.name] = self.field.to_python(value) + + +def make_contrib(superclass, func=None): + """ + Returns a suitable contribute_to_class() method for the Field subclass. + + If 'func' is passed in, it is the existing contribute_to_class() method on + the subclass and it is called before anything else. It is assumed in this + case that the existing contribute_to_class() calls all the necessary + superclass methods. + """ + def contribute_to_class(self, cls, name, **kwargs): + if func: + func(self, cls, name, **kwargs) + else: + super(superclass, self).contribute_to_class(cls, name, **kwargs) + setattr(cls, self.name, Creator(self)) + + return contribute_to_class + + class FileBrowseAndUploadWidget(Input): input_type = 'text' @@ -107,7 +156,7 @@ def clean(self, value): return value -class FileBrowseAndUploadField(with_metaclass(models.SubfieldBase, CharField)): +class FileBrowseAndUploadField(with_metaclass(SubfieldBase, CharField)): description = "FileBrowseAndUploadField" From 94ee1bb0b365ded81f7733852aa1a141f0238e47 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Fri, 31 May 2019 00:17:49 +0800 Subject: [PATCH 3/9] fix django1.11 compatible issue --- browse_and_upload_field/fields.py | 4 ++-- .../templates/filebrowser/custom_browse_and_upload_field.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index 7331cb1..b4be2ee 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -110,7 +110,7 @@ def render(self, name, value, attrs=None): value = "" if value != "" and not isinstance(value, FileObject): value = FileObject(value, site=self.site) - final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) + final_attrs = self.build_attrs(self.attrs, attrs) final_attrs['search_icon'] = static('filebrowser/img/filebrowser_icon_show.gif') final_attrs['url'] = url final_attrs['directory'] = self.directory or self.upload_to @@ -148,7 +148,7 @@ def __init__(self, max_length=None, min_length=None, site=None, directory=None, def clean(self, value): value = super(FileBrowseAndUploadFormField, self).clean(value) - if value == '': + if not value: return value file_extension = os.path.splitext(value)[1].lower() if self.extensions and file_extension not in self.extensions: diff --git a/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html b/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html index 55aeb79..fd81bb1 100644 --- a/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html +++ b/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html @@ -10,7 +10,7 @@ {% if value.filetype == "Image" %} - {% version_object value.path final_attrs.ADMIN_THUMBNAIL as thumbnail_version %} + {% version value.path final_attrs.ADMIN_THUMBNAIL as thumbnail_version %} {% if thumbnail_version %}

From a1647ff448f0801fbb9874281a6da57080864704 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Tue, 11 Jun 2019 12:11:56 +0800 Subject: [PATCH 4/9] fix FileBrowseAndUploadField for django1.11 --- browse_and_upload_field/fields.py | 102 +++++++++++------------------- 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index b4be2ee..f5e7621 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -3,6 +3,8 @@ # PYTHON IMPORTS import os +from django.utils.six import string_types + # DJANGO IMPORTS from django.conf import settings from django.core import urlresolvers @@ -17,62 +19,14 @@ from django.utils.six import with_metaclass from django.utils.translation import ugettext_lazy as _ from django.contrib.admin.templatetags.admin_static import static +from django.contrib.admin.options import FORMFIELD_FOR_DBFIELD_DEFAULTS # FILEBROWSER IMPORTS -from filebrowser.settings import UPLOAD_TEMPDIR, ADMIN_THUMBNAIL, EXTENSIONS from filebrowser.base import FileObject +from filebrowser.settings import ADMIN_THUMBNAIL, EXTENSIONS, UPLOAD_TEMPDIR from filebrowser.sites import site -class SubfieldBase(type): - """ - A metaclass for custom Field subclasses. This ensures the model's attribute - has the descriptor protocol attached to it. - """ - def __new__(cls, name, bases, attrs): - - new_class = super(SubfieldBase, cls).__new__(cls, name, bases, attrs) - new_class.contribute_to_class = make_contrib( - new_class, attrs.get('contribute_to_class') - ) - return new_class - - -class Creator(object): - """ - A placeholder class that provides a way to set the attribute on the model. - """ - def __init__(self, field): - self.field = field - - def __get__(self, obj, type=None): - if obj is None: - return self - return obj.__dict__[self.field.name] - - def __set__(self, obj, value): - obj.__dict__[self.field.name] = self.field.to_python(value) - - -def make_contrib(superclass, func=None): - """ - Returns a suitable contribute_to_class() method for the Field subclass. - - If 'func' is passed in, it is the existing contribute_to_class() method on - the subclass and it is called before anything else. It is assumed in this - case that the existing contribute_to_class() calls all the necessary - superclass methods. - """ - def contribute_to_class(self, cls, name, **kwargs): - if func: - func(self, cls, name, **kwargs) - else: - super(superclass, self).contribute_to_class(cls, name, **kwargs) - setattr(cls, self.name, Creator(self)) - - return contribute_to_class - - class FileBrowseAndUploadWidget(Input): input_type = 'text' @@ -92,7 +46,9 @@ class Media: def __init__(self, attrs=None): super(FileBrowseAndUploadWidget, self).__init__(attrs) - self.site = attrs.get('filebrowser_site', '') + self.site = attrs.get('filebrowser_site', None) + #self.site = attrs.get('site', '') + print(self.site) self.directory = attrs.get('directory', '') self.extensions = attrs.get('extensions', '') self.format = attrs.get('format', '') @@ -104,13 +60,13 @@ def __init__(self, attrs=None): self.attrs = {} super(FileBrowseAndUploadWidget, self).__init__(attrs) - def render(self, name, value, attrs=None): + def render(self, name, value, attrs=None, renderer=None): url = urlresolvers.reverse(self.site.name + ":fb_browse") if value is None: value = "" if value != "" and not isinstance(value, FileObject): value = FileObject(value, site=self.site) - final_attrs = self.build_attrs(self.attrs, attrs) + final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) final_attrs['search_icon'] = static('filebrowser/img/filebrowser_icon_show.gif') final_attrs['url'] = url final_attrs['directory'] = self.directory or self.upload_to @@ -129,7 +85,13 @@ def render(self, name, value, attrs=None): pass return render_to_string("filebrowser/custom_browse_and_upload_field.html", locals()) - + def build_attrs(self, extra_attrs=None, **kwargs): + "Helper function for building an attribute dictionary." + attrs = dict(self.attrs, **kwargs) + if extra_attrs: + attrs.update(extra_attrs) + return attrs + class FileBrowseAndUploadFormField(forms.CharField): default_error_messages = { @@ -156,7 +118,7 @@ def clean(self, value): return value -class FileBrowseAndUploadField(with_metaclass(SubfieldBase, CharField)): +class FileBrowseAndUploadField(CharField): description = "FileBrowseAndUploadField" @@ -175,6 +137,9 @@ def to_python(self, value): return value return FileObject(value, site=self.site) + def from_db_value(self, value, expression, connection, context): + return self.to_python(value) + def get_db_prep_value(self, value, connection, prepared=False): if not value: return value @@ -184,18 +149,20 @@ def get_db_prep_value(self, value, connection, prepared=False): return value def get_prep_value(self, value): - if not value: + if not value or isinstance(value, string_types): return value return value.path def value_to_string(self, obj): - value = self._get_val_from_obj(obj) + value = self.value_from_object(obj) if not value: return value return value.path def formfield(self, **kwargs): + widget_class = kwargs.get('widget', FileBrowseAndUploadWidget) attrs = {} + attrs["site"] = self.site attrs["filebrowser_site"] = self.site attrs["directory"] = self.directory attrs["extensions"] = self.extensions @@ -204,7 +171,8 @@ def formfield(self, **kwargs): attrs["temp_upload_dir"] = self.temp_upload_dir defaults = { 'form_class': FileBrowseAndUploadFormField, - 'widget': FileBrowseAndUploadWidget(attrs=attrs), + 'widget': widget_class(attrs=attrs), + 'site': self.site, 'filebrowser_site': self.site, 'directory': self.directory, 'extensions': self.extensions, @@ -215,20 +183,20 @@ def formfield(self, **kwargs): return super(FileBrowseAndUploadField, self).formfield(**defaults) def upload_callback(self, sender, instance, **kwargs): - opts = instance._meta - field = getattr(instance, self.name) + value = getattr(instance, self.name) + if not value or isinstance(value, string_types): + return value - if field: - - filename = os.path.basename(smart_text(field.filename)) + if value and getattr(value, 'filename', None): + filename = os.path.basename(smart_text(value.filename)) upload_to = opts.get_field(self.name).upload_to filebrowser_directory = self.site.directory if getattr(upload_to, '__call__', None): upload_to = os.path.split(upload_to(instance, filename))[0] - if self.temp_upload_dir in field.path: + if self.temp_upload_dir in value.path: new_file = get_storage_class()().get_available_name( os.path.join( settings.MEDIA_ROOT, @@ -241,7 +209,7 @@ def upload_callback(self, sender, instance, **kwargs): if not os.path.isdir(new_path): os.makedirs(new_path) os.chmod(new_path, 0o775) - file_move_safe(os.path.join(settings.MEDIA_ROOT, field.path), new_file, allow_overwrite=False) + file_move_safe(os.path.join(settings.MEDIA_ROOT, value.path), new_file, allow_overwrite=False) os.chmod(new_file, 0o775) setattr(instance, self.name, new_file.replace(settings.MEDIA_ROOT + "/", "")) instance.save() @@ -249,6 +217,7 @@ def upload_callback(self, sender, instance, **kwargs): # Now generate all versions if this is an image if self.format.title() == 'Image': for v in settings.FILEBROWSER_VERSIONS: + instance.refresh_from_db() # Getattr again as the property has been changed version = getattr(instance, self.name).version_generate(v) os.chmod(os.path.join(settings.MEDIA_ROOT, version.path), 0o775) @@ -258,6 +227,9 @@ def contribute_to_class(self, cls, name): super(FileBrowseAndUploadField, self).contribute_to_class(cls, name) +FORMFIELD_FOR_DBFIELD_DEFAULTS[FileBrowseAndUploadField] = {'widget': FileBrowseAndUploadWidget} + + if 'south' in settings.INSTALLED_APPS: from south.modelsinspector import add_introspection_rules add_introspection_rules([], ["^filebrowser\.fields\.FileBrowseAndUploadField"]) From eac058aebf4323bb655b3358db78c7d9c28206f5 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Fri, 14 Jun 2019 00:38:39 +0800 Subject: [PATCH 5/9] bug fix for value_to_string, return value when value is string_types --- browse_and_upload_field/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index f5e7621..029354d 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -155,7 +155,7 @@ def get_prep_value(self, value): def value_to_string(self, obj): value = self.value_from_object(obj) - if not value: + if not value or isinstance(value, string_types): return value return value.path From d8c88042ce567adf9d9a3e81ab34a6f6c2783b42 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Fri, 28 Jun 2019 20:25:45 +0800 Subject: [PATCH 6/9] remove debug print statement --- browse_and_upload_field/fields.py | 1 - 1 file changed, 1 deletion(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index 029354d..a3593c6 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -48,7 +48,6 @@ def __init__(self, attrs=None): super(FileBrowseAndUploadWidget, self).__init__(attrs) self.site = attrs.get('filebrowser_site', None) #self.site = attrs.get('site', '') - print(self.site) self.directory = attrs.get('directory', '') self.extensions = attrs.get('extensions', '') self.format = attrs.get('format', '') From f3e02e565725ab44c380587f11cfe832a6996117 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Tue, 20 Aug 2019 14:14:23 +0800 Subject: [PATCH 7/9] django 2.2: The django.core.urlresolvers module is removed in favor of its new location, django.urls. --- browse_and_upload_field/site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browse_and_upload_field/site.py b/browse_and_upload_field/site.py index 69b11f0..0081c93 100644 --- a/browse_and_upload_field/site.py +++ b/browse_and_upload_field/site.py @@ -2,7 +2,7 @@ import os import re -from django.core.urlresolvers import reverse +from django.urls import reverse from django.http import HttpResponse, HttpResponseBadRequest from django.utils.encoding import smart_text From fdfed28722825e2c635043c1f916dd53bd8cd177 Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Tue, 20 Aug 2019 14:44:54 +0800 Subject: [PATCH 8/9] django 2.2: The django.core.urlresolvers module is removed in favor of its new location, django.urls. --- browse_and_upload_field/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index a3593c6..728e2aa 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -7,7 +7,7 @@ # DJANGO IMPORTS from django.conf import settings -from django.core import urlresolvers +from django.urls import reverse from django.core.files.move import file_move_safe from django.core.files.storage import get_storage_class from django.db import models @@ -60,7 +60,7 @@ def __init__(self, attrs=None): super(FileBrowseAndUploadWidget, self).__init__(attrs) def render(self, name, value, attrs=None, renderer=None): - url = urlresolvers.reverse(self.site.name + ":fb_browse") + url = reverse(self.site.name + ":fb_browse") if value is None: value = "" if value != "" and not isinstance(value, FileObject): From 0dde74ee91b31e3fd3b059a900e8ef66a5c4612d Mon Sep 17 00:00:00 2001 From: Chen Zhe Date: Thu, 28 Dec 2023 17:47:29 +0800 Subject: [PATCH 9/9] fixes for python-3.12 and django-4.2.8 --- browse_and_upload_field/fields.py | 14 +++++--------- browse_and_upload_field/site.py | 14 +++++++------- .../custom_browse_and_upload_field.html | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/browse_and_upload_field/fields.py b/browse_and_upload_field/fields.py index 728e2aa..7e6c05a 100644 --- a/browse_and_upload_field/fields.py +++ b/browse_and_upload_field/fields.py @@ -15,10 +15,10 @@ from django import forms from django.forms.widgets import Input from django.template.loader import render_to_string -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.utils.six import with_metaclass -from django.utils.translation import ugettext_lazy as _ -from django.contrib.admin.templatetags.admin_static import static +from django.utils.translation import gettext_lazy as _ +from django.templatetags.static import static from django.contrib.admin.options import FORMFIELD_FOR_DBFIELD_DEFAULTS # FILEBROWSER IMPORTS @@ -136,7 +136,7 @@ def to_python(self, value): return value return FileObject(value, site=self.site) - def from_db_value(self, value, expression, connection, context): + def from_db_value(self, value, expression, connection, context=None): return self.to_python(value) def get_db_prep_value(self, value, connection, prepared=False): @@ -188,7 +188,7 @@ def upload_callback(self, sender, instance, **kwargs): return value if value and getattr(value, 'filename', None): - filename = os.path.basename(smart_text(value.filename)) + filename = os.path.basename(smart_str(value.filename)) upload_to = opts.get_field(self.name).upload_to filebrowser_directory = self.site.directory @@ -228,7 +228,3 @@ def contribute_to_class(self, cls, name): FORMFIELD_FOR_DBFIELD_DEFAULTS[FileBrowseAndUploadField] = {'widget': FileBrowseAndUploadWidget} - -if 'south' in settings.INSTALLED_APPS: - from south.modelsinspector import add_introspection_rules - add_introspection_rules([], ["^filebrowser\.fields\.FileBrowseAndUploadField"]) diff --git a/browse_and_upload_field/site.py b/browse_and_upload_field/site.py index 0081c93..6830216 100644 --- a/browse_and_upload_field/site.py +++ b/browse_and_upload_field/site.py @@ -4,7 +4,7 @@ from django.urls import reverse from django.http import HttpResponse, HttpResponseBadRequest -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from filebrowser import signals from filebrowser.base import FileObject @@ -65,20 +65,20 @@ def _upload_file(self, request): uploadedfile = handle_file_upload(path, filedata, site=self) if file_already_exists and OVERWRITE_EXISTING: - old_file = smart_text(file_path) - new_file = smart_text(uploadedfile) + old_file = smart_str(file_path) + new_file = smart_str(uploadedfile) self.storage.move(new_file, old_file, allow_overwrite=True) - full_path = FileObject(smart_text(old_file), site=self).path_full + full_path = FileObject(smart_str(old_file), site=self).path_full else: - file_name = smart_text(uploadedfile) + file_name = smart_str(uploadedfile) filedata.name = os.path.relpath(file_name, path) - full_path = FileObject(smart_text(file_name), site=self).path_full + full_path = FileObject(smart_str(file_name), site=self).path_full # set permissions if DEFAULT_PERMISSIONS is not None: os.chmod(full_path, DEFAULT_PERMISSIONS) - f = FileObject(smart_text(file_name), site=self) + f = FileObject(smart_str(file_name), site=self) signals.filebrowser_post_upload.send(sender=request, path=folder, file=f, site=self) # We don't know at this stage if it's an image diff --git a/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html b/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html index fd81bb1..7bf9c7f 100644 --- a/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html +++ b/browse_and_upload_field/templates/filebrowser/custom_browse_and_upload_field.html @@ -1,4 +1,4 @@ -{% load i18n fb_versions staticfiles %} +{% load i18n fb_versions static %}

- \ No newline at end of file +