GithubHelp home page GithubHelp logo

barttc / django-attachments Goto Github PK

View Code? Open in Web Editor NEW
294.0 13.0 90.0 204 KB

A generic Django application to attach Files (Attachments) to any model.

License: BSD 3-Clause "New" or "Revised" License

Python 97.34% HTML 2.66%

django-attachments's Introduction

https://travis-ci.org/bartTC/django-attachments.svg?branch=master Codacy Badge https://api.codacy.com/project/badge/Coverage/e13db6df2a2148b08c662798642aa611

django-attachments

django-attachments is a generic set of template tags to attach any kind of files to models.

Installation:

  1. Put attachments to your INSTALLED_APPS in your settings.py within your django project:

    INSTALLED_APPS = (
        ...
        'attachments',
    )
  2. Add the attachments urlpattern to your urls.py:

    url(r'^attachments/', include('attachments.urls', namespace='attachments')),
  3. Migrate your database:

    ./manage.py migrate
  4. Grant the user some permissions:

    • For adding attachments grant the user (or group) the permission attachments.add_attachment.
    • For deleting attachments grant the user (or group) the permission attachments.delete_attachment. This allows the user to delete their attachments only.
    • For deleting foreign attachments (attachments by other users) grant the user the permission attachments.delete_foreign_attachments.
  5. Set DELETE_ATTACHMENTS_FROM_DISK to True if you want to remove files from disk when Attachment objects are removed!

  6. Configure FILE_UPLOAD_MAX_SIZE (optional). This is the maximum size in bytes before raising form validation errors. If not set there is no restriction on file size.

Mind that you serve files!

django-attachments stores the files in your site_media directory and does not modify them. For example, if an user uploads a .html file your webserver will probably display it in HTML. It's a good idea to serve such files as plain text. In a Apache2 configuration this would look like:

<Location /site_media/attachments>
    AddType text/plain .html .htm .shtml .php .php5 .php4 .pl .cgi
</Location>

House-keeping

django-attachments provides the delete_stale_attachments management command. It will remove all attachments for which the related objects don't exist anymore! Sys-admins could then:

./manage.py delete_stale_attachments

You may also want to execute this via cron.

Local development

Installing a local devel environment with pipenv. It creates a virtualenv for you with the right ENV variables loaded from .env.

# pip install pipenv

$ pipenv install
Loading .env environment variables...
Installing dependencies from Pipfile.lock (a053bc)...
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.

Tests

Run the testsuite in your local environment using pipenv:

$ cd django-attachments/
$ pipenv install --dev
$ pipenv run pytest attachments/

Or use tox to test against various Django and Python versions:

$ tox -r

You can also invoke the test suite or other 'manage.py' commands by calling the django-admin tool with the test app settings:

$ cd django-attachments/
$ pipenv install --dev
$ pipenv run test
$ pipenv run django-admin.py runserver
$ pipenv run django-admin makemigrations --dry-run

Building a new release

$ git tag
$ change version in setup.cfg
$ pip install -U setuptools
$ python setup.py sdist && python setup.py bdist_wheel --universal
$ twine upload --sign dist/*

Usage:

In contrib.admin:

django-attachments provides a inline object to add a list of attachments to any kind of model in your admin app.

Simply add AttachmentInlines to the admin options of your model. Example:

from django.contrib import admin
from attachments.admin import AttachmentInlines

class MyEntryOptions(admin.ModelAdmin):
    inlines = (AttachmentInlines,)

http://cloud.github.com/downloads/bartTC/django-attachments/attachments_screenshot_admin.png

In your frontend templates:

First of all, load the attachments_tags in every template you want to use it:

{% load attachments_tags %}

django-attachments comes with some templatetags to add or delete attachments for your model objects in your frontend.

  1. get_attachments_for [object]: Fetches the attachments for the given model instance. You can optionally define a variable name in which the attachment list is stored in the template context (this is required in Django 1.8). If you do not define a variable name, the result is printed instead.

    {% get_attachments_for entry as attachments_list %}
  2. attachments_count [object]: Counts the attachments for the given model instance and returns an int:

    {% attachments_count entry %}
  3. attachment_form: Renders a upload form to add attachments for the given model instance. Example:

    {% attachment_form [object] %}

    It returns an empty string if the current user is not logged in.

  4. attachment_delete_link: Renders a link to the delete view for the given attachment. Example:

    {% for att in attachments_list %}
        {{ att }} {% attachment_delete_link att %}
    {% endfor %}

    This tag automatically checks for permission. It returns only a html link if the give n attachment's creator is the current logged in user or the user has the delete_foreign_attachments permission.

Quick Example:

{% load attachments_tags %}
{% get_attachments_for entry as my_entry_attachments %}

<span>Object has {% attachments_count entry %} attachments</span>
{% if my_entry_attachments %}
<ul>
{% for attachment in my_entry_attachments %}
    <li>
        <a href="{{ attachment.attachment_file.url }}">{{ attachment.filename }}</a>
        {% attachment_delete_link attachment %}
    </li>
{% endfor %}
</ul>
{% endif %}

{% attachment_form entry %}

{% if messages %}
<ul class="messages">
{% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
        {{ message }}
    </li>
{% endfor %}
</ul>
{% endif %}

Settings

  • DELETE_ATTACHMENTS_FROM_DISK will delete attachment files when the attachment model is deleted. Default False!
  • FILE_UPLOAD_MAX_SIZE in bytes. Deny file uploads exceeding this value. Undefined by default.
  • AppConfig.attachment_validators - a list of custom form validator functions which will be executed against uploaded files. If any of them raises ValidationError the upload will be denied. Empty by default. See attachments/tests/testapp/apps.py for an example.

django-attachments's People

Contributors

aert avatar aleksihakli avatar anentropic avatar atodorov avatar barttc avatar bashu avatar chathaway-codes avatar darkpixel avatar dependabot[bot] avatar flimm avatar gilsondev avatar gonzalobustos avatar jangeador avatar jeverling avatar jezdez avatar maltalk avatar mattburlage avatar morlandi avatar reb00ter avatar vitan avatar yesnik avatar zulupro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-attachments's Issues

Integrate with django-storages.

Would be really nice if django-attachments could integrate with "upload_to" on django-storages. We could then upload attachments to different storage containers without too much work.

For details see:
http://bitbucket.org/david/django-storages/

I have done some code changes, but they are not ready to be integrated into the existing module. Would it help if I forked this repository so we could discuss the changes?

Thanks

Is django-attachments compatible with django 1.8?

Do I have to add an attachments field to my models that I wish to attach attachments to?

VariableDoesNotExist at /testproject/requirements/1/
Failed lookup for key [attachments] in u"[{'False': False, 'None': None, 'True': True}, {}, {}, {'project': <Project: testproject>, 'requirement': <Requirement: 1: A test requirement.>, u'object': <Requirement: 1: A test requirement.>, u'view': <requirements.views.RequirementRead object at 0x7f4fa42bf890>}]"
Request Method: GET
Request URL:    http://localhost:8000/testproject/requirements/1/
Django Version: 1.8.5
Exception Type: VariableDoesNotExist
Exception Value:    
Failed lookup for key [attachments] in u"[{'False': False, 'None': None, 'True': True}, {}, {}, {'project': <Project: testproject>, 'requirement': <Requirement: 1: A test requirement.>, u'object': <Requirement: 1: A test requirement.>, u'view': <requirements.views.RequirementRead object at 0x7f4fa42bf890>}]"
Exception Location: /home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/template/base.py in _resolve_lookup, line 839
Python Executable:  /home/erich/.virtualenvs/reqtangle/bin/python
Python Version: 2.7.6
Python Path:    
['/home/erich/src/reqtangle/reqtangle',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7/plat-x86_64-linux-gnu',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7/lib-tk',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7/lib-old',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7/lib-dynload',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-x86_64-linux-gnu',
 '/usr/lib/python2.7/lib-tk',
 '/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages',
 '/home/erich/.virtualenvs/reqtangle/lib/python2.7/site-packages']
Server time:    Thu, 22 Oct 2015 15:18:33 +0000

Pipfile vs tox.ini

@bartTC what is Pipfile and what is it used for?

My original reason for asking is that I see Pipfile.lock which has lots of outdated dependencies but these are not dependencies we ship via setup.py/setup.cfg so not sure what they represent. Looks like something old.

Then I've noticed that Pipfile uses pytest to execute the test suite however .travis-ci.yml which I'm trying to convert into GitHub actions uses tox instead. It looks like there are 2 different ways to execute tests.

Given that Pipfile is older and hasn't seen any updates recently I'm thinking we could remove it in favor of GitHub Actions + tox ?

Does `python_2_unicode_compatible` break in a current version?

Related issue: jazzband/django-auditlog#231

"attachments\models.py", line 9

Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
  File "C:\python-3.7.4.amd64\lib\threading.py", line 926, in _bootstrap_inner
    self.run()
  File "C:\python-3.7.4.amd64\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "C:\python-3.7.4.amd64\lib\site-packages\django\utils\autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "C:\python-3.7.4.amd64\lib\site-packages\django\core\management\commands\runserver.py", line 109, in inner_run
    autoreload.raise_last_exception()
  File "C:\python-3.7.4.amd64\lib\site-packages\django\utils\autoreload.py", line 76, in raise_last_exception
    raise _exception[1]
  File "C:\python-3.7.4.amd64\lib\site-packages\django\core\management\__init__.py", line 357, in execute
    autoreload.check_errors(django.setup)()
  File "C:\python-3.7.4.amd64\lib\site-packages\django\utils\autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "C:\python-3.7.4.amd64\lib\site-packages\django\__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "C:\python-3.7.4.amd64\lib\site-packages\django\apps\registry.py", line 114, in populate
    app_config.import_models()
 File "C:\python-3.7.4.amd64\lib\site-packages\django\apps\config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "C:\python-3.7.4.amd64\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "C:\python-3.7.4.amd64\lib\site-packages\attachments\models.py", line 9, in <module>
    from django.utils.encoding import python_2_unicode_compatible
ImportError: cannot import name 'python_2_unicode_compatible' from 'django.utils.encoding' (C:\python-3.7.4.amd64\lib\site-packages\django\utils\encoding.py)

Italian translation

Hello,
Sorry for my English...
I translated django-attachments in italian, I would be pleased if this patch will be included in the current branch.

commit aca1077187218445fb11ea1bd3a18492a5e7494a
Author: Scope Emanuele [email protected]
Date: Fri Dec 30 21:58:22 2011 +0100

Add italian translation

diff --git a/attachments/locale/it/LC_MESSAGES/django.mo b/attachments/locale/it/LC_MESSAGES/django.mo
new file mode 100644
index 0000000..e6ccd3b
Binary files /dev/null and b/attachments/locale/it/LC_MESSAGES/django.mo differ
diff --git a/attachments/locale/it/LC_MESSAGES/django.po b/attachments/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 0000000..89794cb
--- /dev/null
+++ b/attachments/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,55 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR EMAIL@ADDRESS, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-12-30 19:47+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME EMAIL@ADDRESS\n"
+"Language-Team: LANGUAGE [email protected]\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: forms.py:7
+msgid "Upload attachment"
+msgstr "Carica allegato"
+
+#: models.py:29
+msgid "creator"
+msgstr "autore"
+
+#: models.py:30
+msgid "attachment"
+msgstr "allegato"
+
+#: models.py:31
+msgid "created"
+msgstr "creato"
+
+#: models.py:32
+msgid "modified"
+msgstr "modificato"
+
+#: views.py:33
+msgid "Your attachment was uploaded."
+msgstr "Il tuo allegato รจ stato caricato."
+
+#: views.py:51
+msgid "Your attachment was deleted."
+msgstr "Il tuo allegato รจ stato cancellato"
+
+#: templates/attachments/add_form.html:7
+msgid "Add attachment"
+msgstr "Aggiungi allegato"
+
+#: templates/attachments/delete_link.html:2
+msgid "Delete attachment"
+msgstr "Cancella allegato"

Attach additional custom metadata

Is there a simple way to attach some custom metadata to the files being uploaded without forking the code overriding the views, models etc? Would be great e.g. to define attachment kind (not content type, rather a kind of business kind)

django.contrib.contenttypes.generic is deprecated

WARNING 2015-08-30 00:11:02,323 generic 24458 139973617043264 /home/aaron/.virtualenvs/uitintranet/local/lib/python2.7/site-packages/attachments/models.py:6: RemovedInDjango19Warning: django.contrib.contenttypes.generic is deprecated and will be removed in Django 1.9. Its contents have been moved to the fields, forms, and admin submodules of django.contrib.contenttypes.
  from django.contrib.contenttypes import generic

How do I make a new release ?

@bartTC I've merged my 3 PRs, updated changelog & tags and all pushed to GitHub but when I tried
python setup.py bdist_wheel the result was UNKNOWN-0.0.0-py3-none-any.whl.

What command do you use for building the actual packages before uploading them to PyPI ?

Instead of renaming attachments with same name, store them in subdirectories

This is related to kiwitcms/Kiwi#3104

This isas feature request to solve this problem:

If a file is uploaded multiple times, it gets renamed. So if a user downloads the file it has not the intended name and must be renamed.

In our use case the file name is specific and must not be changed in order to be usable by the user.

This is the proposed solution:

Instead of renaming the file, store it in a subdirectory. This will create a unique path without changing the file name.

Add model method that gives path to file with MEDIA_DIR prepended.

Images get uploaded to

STATIC_DIR + /attachments/module_entity/73630/image.jpg

But when getting displayed, the static/media prefix is not respected and it loads the image from

attachments/module_entity/73630/image.jpg => 404

Sidequestion:
Is there a variable to configure to use the current logged in user instead of presenting a selectbox to chose the upload user from?

ImportError: No module named defaults

Environment:


Request Method: GET
Request URL: http://localhost:8000/testproject/requirements/

Django Version: 1.8.5
Python Version: 2.7.6
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'projects',
 'requirements',
 'allauth',
 'allauth.account',
 'allauth.socialaccount',
 'taggit',
 'attachments')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware')


Traceback:
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  119.                 resolver_match = resolver.resolve(request.path_info)
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/core/urlresolvers.py" in resolve
  365.             for pattern in self.url_patterns:
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/core/urlresolvers.py" in url_patterns
  401.         patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/core/urlresolvers.py" in urlconf_module
  395.             self._urlconf_module = import_module(self.urlconf_name)
File "/usr/lib/python2.7/importlib/__init__.py" in import_module
  37.     __import__(name)
File "/home/erich/src/reqtangle/reqtangle/reqtangle/urls.py" in <module>
  26.     url(r'^attachments/', include('attachments.urls', namespace='attachments')),
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/django/conf/urls/__init__.py" in include
  33.         urlconf_module = import_module(urlconf_module)
File "/usr/lib/python2.7/importlib/__init__.py" in import_module
  37.     __import__(name)
File "/home/erich/.virtualenvs/reqtangle/local/lib/python2.7/site-packages/attachments/urls.py" in <module>
  1. from django.conf.urls.defaults import *

Exception Type: ImportError at /testproject/requirements/
Exception Value: No module named defaults

Error on click to attachment download link

Dear, thanks for the application, very usefull and good.
can someone help me, I have all working with tags, load attachemnt save on media directory but when I click on download link it send

expected str, bytes or os.PathLike object, not NoneType

delete link is working on file deletion database.

here my settings
BASE_DIR => /home/workspace/sgm_maudal
STATIC_URL => /manutenzione/static/
STATIC_ROOT => /home/workspace/sgm_maudal/manutenzione/static
MEDIA_ROOT => /home/workspace/sgm_maudal/media
MEDIA_URL => /media/

immagine

immagine

It worked many times and after, when I add qr-code with pip installation get the erro.
I dont think problem is qr-code, may be my mistake.

Thanks
regards

NoReverseMatch exception using with models that have columns of type uuid4 as primary key

Thank you for this wonderful project. I can't find a way to use it with models that have columns of type uuid as primary key.

Traceback (most recent call last):
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 202, in _get_response
    response = response.render()
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/response.py", line 105, in render
    self.content = self.rendered_content
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/response.py", line 83, in rendered_content
    return template.render(context, self._request)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 170, in render
    return self._render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 162, in _render
    return self.nodelist.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/template/library.py", line 214, in render
    _dict = self.func(*resolved_args, **resolved_kwargs)
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/attachments/templatetags/attachments_tags.py", line 22, in attachment_form
    "form_url": add_url_for_obj(obj),
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/attachments/views.py", line 20, in add_url_for_obj
    return reverse(
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "/home/usuario/Documentos/dev/awesome-project/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
    raise NoReverseMatch(msg)

Exception Type: NoReverseMatch at /finances/customers/bc74f90a-5225-45c0-86ed-c70faf71453e/detail
Exception Value: Reverse for 'add' with keyword arguments '{'app_label': 'finances', 'model_name': 'customer', 'pk': UUID('bc74f90a-5225-45c0-86ed-c70faf71453e')}' not found. 1 pattern(s) tried: ['attachments/add-for/(?P<app_label>[\\w\\-]+)/(?P<model_name>[\\w\\-]+)/(?P<pk>\\d+)/$']

Doc issue

You have a typo in docs. You define:

{{{
{% get_attachments_for entry as "attachments_list" %}
}}

And in then you use attachment_list (without s) in other example. This result in an invalid template code if you cut paste the doc example in a template. No attachment are visible by the end user.

Use in multitenant applications

Hi Martin (@bartTC),

Thanks for this module. This is really great and I am enjoying using this. I wanted to know how I can do the following (if possible):

  1. I want to use this with django-tenant-schemas. For this to work, I need a way to change where the files are stored to include a tenant id in the path. How would I do this? Is there a function I can define in setting that allows me to customize the path per tenant?

  2. Again for the case above I need to add authorization so that files from one schema cannot be seen/opened by another. That means there needs to be an interceptor for such requests. Any suggestion regarding this?

  3. Even within the same schema/tenant I want to restrict files (if someone directly enters a URL) to be restricted to owner. How can I do this?

  4. Instead of filenames, I would like to rename the files as UUID/GUID. Is there something I can define or override to do this?

Thanks
Amit

Question: using django-attachments with a dynamic text editor

@bartTC I have a question, or rather looking for other points of view and ideas.

The gist is that in a project of mine I have several Models which accept attachments as well as Markdown text. The attachments are nicely displayed for each Model's get.html page (all rendered via templates, these are mostly DetailViews). Now users want to have an image upload button in the JavaScript editor (it's SimpleMDE) akin to what the GitHub editor does - select a file from their PC and it will be uploaded to the server and then the appropriate Markdown will be automatically placed for them.

The way GitHub does it is by pinning the attachments to the user ID b/c that's about the only thing known at any given time. We can do the same with django-attachments but it opens a whole lot more questions how to deal with these files, see:
kiwitcms/Kiwi#977 (comment)

This idea with per-user attachments also doesn't work well for my existing architecture where attachments are displayed in the details template for each object.

Any ideas, hints or recommendations from your side ?

UnicodeEncodeError

It looks like somebody tried to upload a file with a funky name to @kiwitcms/Kiwi and we got this traceback in Sentry:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 57-58: ordinal not in range(128)
  File "django/core/handlers/exception.py", line 35, in inner
    response = get_response(request)
  File "django/core/handlers/base.py", line 128, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "django/core/handlers/base.py", line 126, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/decorators/http.py", line 40, in inner
    return func(request, *args, **kwargs)
  File "django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "attachments/views.py", line 50, in add_attachment
    form.save(request, obj)
  File "attachments/forms.py", line 29, in save
    super(AttachmentForm, self).save(*args, **kwargs)
  File "django/forms/models.py", line 456, in save
    self.instance.save()
  File "django/db/models/base.py", line 729, in save
    force_update=force_update, update_fields=update_fields)
  File "django/db/models/base.py", line 759, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "django/db/models/base.py", line 842, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "django/db/models/base.py", line 880, in _do_insert
    using=using, raw=raw)
  File "django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "django/db/models/query.py", line 1125, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "django/db/models/sql/compiler.py", line 1283, in execute_sql
    for sql, params in self.as_sql():
  File "django/db/models/sql/compiler.py", line 1236, in as_sql
    for obj in self.query.objs
  File "django/db/models/sql/compiler.py", line 1236, in <listcomp>
    for obj in self.query.objs
  File "django/db/models/sql/compiler.py", line 1235, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "django/db/models/sql/compiler.py", line 1185, in pre_save_val
    return field.pre_save(obj, add=True)
  File "django/db/models/fields/files.py", line 287, in pre_save
    file.save(file.name, file.file, save=False)
  File "django/db/models/fields/files.py", line 87, in save
    self.name = self.storage.save(name, content, max_length=self.field.max_length)
  File "django/core/files/storage.py", line 48, in save
    name = self.get_available_name(name, max_length=max_length)
  File "django/core/files/storage.py", line 72, in get_available_name
    while self.exists(name) or (max_length and len(name) > max_length):
  File "django/core/files/storage.py", line 308, in exists
    return os.path.exists(self.path(name))
  File "python3.5/genericpath.py", line 19, in exists
    os.stat(path)

Let me know what other info I can provide because I'm not able to reproduce locally.

New migration created by Django 2

As part of running ./manage.py makemigrations because I've deleted some models inside my codebase I got the following migration created for django-attachments:

# Generated by Django 2.0 on 2017-12-30 10:19

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('attachments', '0001_initial'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='attachment',
            options={'ordering': ['-created'], 'permissions': (('delete_foreign_attachments', 'Can delete foreign attachments'),), 'verbose_name': 'attachment', 'verbose_name_plural': 'attachments'},
        ),
    ]

The version I have installed is 1.2 from PyPI.

Can you see if this is indeed necessary? Maybe you forgot to call makemigrations before the last release?

Danish locale file

I've created a locale file for the django-attachments app.. Please add it to the project :-)

Attaching files to a new entry

Is there a way to upload attachments with a new form entry? Or must there already be an existing entry to bind to? (sorry for the double post)

FileField 'max_length' is set to default in the attachment. Can we increase this possibly?

Hello! I am working on an application that uses attachments, but I'm running into a limitation of the filenames being truncated because the filename is set to the default of 100. Could we potentially increase this to the windows(as of Windows 10) maximum allowed filename length of 32,767?

Edit: To clarify the Django DB defaults string lengths like this to 255. My application is currently running with a maximum larger than this in the django db settings. So getting attachments to match would be awesome.

Thanks!
Kiowa

Update the relation to point at settings.AUTH_USER_MODEL

I've done the first four step and I got this error:

CommandError: One or more models did not validate:
attachments.attachment: 'creator' defines a relation with the model 'auth.User', which has been swapped out. Update the relation to point at settings.AUTH_USER_MODEL

I'm using Django 1.6.5 with this in my settings.py

AUTH_USER_MODEL = 'core.User'

Set request.user as creator in django-admin.

I'm using django-attachments to upload files in django-admin.

class MyEntryOptions(admin.ModelAdmin):
    inlines = (AttachmentInlines,)

image

Instead of manually specifying the creator I would like to automatically set it to request.user. How can I do that?

Include "Upload from console" in docs

It took me a few minutes of dorking around to figure out how to attach files from the console.
This is useful for importing files into your project.

MyAttachment = File(open('/home/user/picture.jpg', 'r'))
a = Attachment()
a.content_object = MyObject
a.creator = MyUser
a.attachment_file = MyAttachment
a.attachment_file.name =
a.save()

v1.7 db_index for object_id field fails on MariaDB

The reason is that it is a TextField with unknown/unlimited length instead of a CharField with a fixed length. MariaDB (probably MySQL as well) doesn't like this and fails when applying the 0004 migration.

@bashu, @bartTC from the original issue #61 I think a CharField(max_length=64) will work just as fine. Any objections for changing it ?

ValueError: invalid literal for int() with base 10: '24890e2e-3515-4303-ab8c-344737c1d63f'

  File "manage.py", line 27, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 316, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 353, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 203, in handle
    fake_initial=fake_initial,
  File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/usr/local/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/usr/local/lib/python3.6/site-packages/django/db/migrations/migration.py", line 124, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/usr/local/lib/python3.6/site-packages/django/db/migrations/operations/special.py", line 190, in database_forwards
    self.code(from_state.apps, schema_editor)
  File "/app/djangoapp/recipes/migrations/0005_auto_20190722_1031.py", line 29, in migrate_to_imagestore
    a.attachment_file.save(obj.photo.name, File(tmp))
  File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/files.py", line 93, in save
    self.instance.save()
  File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 718, in save
    force_update=force_update, update_fields=update_fields)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 748, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 831, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 869, in _do_insert
    using=using, raw=raw)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py", line 1136, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1288, in execute_sql
    for sql, params in self.as_sql():
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1241, in as_sql
    for obj in self.query.objs
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1241, in <listcomp>
    for obj in self.query.objs
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1240, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1182, in prepare_value
    value = field.get_db_prep_save(value, connection=self.connection)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 790, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 785, in get_db_prep_value
    value = self.get_prep_value(value)
  File "/usr/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1807, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: '24890e2e-3515-4303-ab8c-344737c1d63f'

overriding __str__ does not work on python 3.6

The str method on the Attachment model is not getting interpolated is returning a literal {username} attached {filename}

This model method:

    def __str__(self):
        return _('{username} attached {filename}') % {
            'username': self.creator.get_username(),
            'filename': self.attachment_file.name
        }

Attachments for new entry (info)

Hi Martin,

This is not an issue, it is a request for info, and refers to the front-end:

Django-attachments works fine for me when editing an entry, however - I cannot get it to work when adding a new entry (resulting in creating the entry and adding attachments after, when editing).

Creating a new entry: When I try to add attachments (using the tag {% attachment_form item %}) - for my model's instance I am getting a TemplateSyntaxError:
"Caught VariableDoesNotExist while rendering: Failed lookup for key [item] in u"[[{'form': <myproject.myapp.forms.ItemForm object at 0x8e7ab2c>"

My model's instance name is Item... Am I using this wrong? I've been sitting on this for days now. I am a Django newbie - still getting the basics, I would appreciate your help.

Thank you, Gabriel.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.