Skip to content

Commit

Permalink
optimized app for Django 1.8
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobias Lorenz committed Jan 14, 2016
1 parent 235d623 commit a908614
Show file tree
Hide file tree
Showing 25 changed files with 380 additions and 729 deletions.
9 changes: 6 additions & 3 deletions .gitignore
@@ -1,7 +1,10 @@
*.egg-info/
*.eggs/
*.pyc
/media/
*coverage/
db.sqlite
build/
dist/
docs/build/
user_media/tests/coverage/
.coverage
*media/
*.tox/
33 changes: 29 additions & 4 deletions .travis.yml
@@ -1,6 +1,31 @@
language: python

python:
- "2.6"
- "2.7"
install: pip install -r requirements.txt --use-mirrors
script: python user_media/tests/runtests.py
- "2.7"
- "3.4"

env:
- DJANGO=django==1.4.*
- DJANGO=django==1.5.*
- DJANGO=django==1.6.*
- DJANGO=django==1.7.*
- DJANGO=django==1.8.*

install:
- pip install -r test_requirements.txt --use-mirrors
- pip install $DJANGO
- pip install coveralls

script:
- cd VAR_PACKAGE_NAME/tests
- ./runtests.py
- mv .coverage ../../
- cd ../../

matrix:
exclude:
- python: "3.4"
env: DJANGO=django==1.4.*

after_success:
- coveralls
4 changes: 4 additions & 0 deletions CHANGELOG.txt
@@ -1,5 +1,9 @@
=== (ongoing) ===

- Replaced factory boy with mixer
- Optimized app for Django 1.8
- Added initial image in form mixin

=== 1.1.X ===

- Fixed UserMediaImage.box_coordinates
Expand Down
73 changes: 24 additions & 49 deletions README.rst
Expand Up @@ -5,35 +5,27 @@ Almost all modern web apps allow their users to upload content such as audio,
video or images. This raises a number of issues if that content should not be
visible to the whole world by default.

If you have a UserProfile model and add an ImageField to it, you need to
come up with a good idea on how to save those images. It is probably not a good
idea to keep the original filenames as they might disturb your server's file
system and open doors for hackers, who might try to brute-force against your
If you add an ImageField to your user model, you need to come up with a good
idea on how to save those images. It is probably not a good idea to keep the
original filenames as they might disturb your server's file system and open
doors for hackers, who might try to brute-force against your
``/media/user_profiles/`` in the hope to steal some valuable files.

Since it seems inevitable to implement a function for Django's FileField's
``upload_to`` attribute I thought that this might be a candidate for a reusable
app.

**This project is experimental**. We are using it on two completely different
live projects and will hopefully come up with an implementation that is so
generic that it can safely be used by anyone.

Since we are dealing with files here and not only with a database, backwards
incompatible changes might turn out to be a pain in the ass to deploy on your
production sites. You have been warned.


Prerequisites
-------------

You need at least the following packages in your virtualenv:

* Django 1.4
* Django
* django-libs
* South

TODO: Test if this really is all we need
* easy_thumbnails
* django-generic-positions
* simplejson


Installation
Expand All @@ -52,7 +44,10 @@ Add the app to your ``INSTALLED_APPS``::
INSTALLED_APPS = [
...
'user_media',
'easy_thumbnails',
'django_libs',
'generic_positions',

]

Hook the app into your main ``urls.py``::
Expand All @@ -62,7 +57,7 @@ Hook the app into your main ``urls.py``::
url(r'^umedia/', include('user_media.urls')),
)

Run the south migrations to create the app's database tables::
Run the migrations to create the app's database tables::

$ ./manage.py migrate user_media

Expand All @@ -82,6 +77,7 @@ model::

from django.contrib.contenttypes import generic


class UserProfile(models.Model):
...
user = models.ForeignKey(
Expand Down Expand Up @@ -121,7 +117,6 @@ In your templates you can now provide a link to the image creation view like
this (assuming that your ``UserProfile`` object is called ``object`` in the
template's context)::

{% load url from future %}
<a href="{% url "user_media_image_create" content_type="userprofile" object_id=object.pk %}">Upload your picture</a>

Note that ``userprofile`` is the model name that the ``ContentType`` of your
Expand Down Expand Up @@ -345,41 +340,21 @@ Amount of images to be uploaded at a maximum.
Contribute
----------

If you want to contribute to this project, please perform the following steps::
If you want to contribute to this project, please perform the following steps

.. code-block:: bash
# Fork this repository
# Clone your fork
$ mkvirtualenv -p python2.7 django-user-media
$ pip install -r requirements.txt
mkvirtualenv -p python2.7 django-user-media
make develop
$ git co -b feature_branch master
git co -b feature_branch master
# Implement your feature and tests
$ git add . && git commit
$ git push -u origin feature_branch
git add . && git commit
git push -u origin feature_branch
# Send us a pull request for your feature branch

Testing
-------

If you want to contribute to this project you can run the tests without setting
up a Django project. Just clone this repository and execute the
``runtests.py``::

$ ./user_media/tests/runtests.py

Sometimes a new feature needs new South migrations, in this case you should
do the following::

$ rm db.sqlite
$ ./manage.py syncdb --migrate
$ ./manage.py schemamigration user_media --auto


Discuss
-------

If you have questions or issues, please open an issue on GitHub.

If we don't react quickly, please don't hesitate to ping me on Twitter
(`@mbrochh <https://twitter.com/mbrochh>`_)
In order to run the tests, simply execute ``tox``. This will install two new
environments (for Django 1.7 and Django 1.8) and run the tests against both
environments.
8 changes: 5 additions & 3 deletions manage.py
Expand Up @@ -2,8 +2,10 @@
import os
import sys

if __name__ == '__main__':
os.environ.setdefault(
'DJANGO_SETTINGS_MODULE', 'user_media.tests.south_settings')
if __name__ == "__main__":
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'user_media.tests.settings')

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
26 changes: 6 additions & 20 deletions requirements.txt
Expand Up @@ -3,23 +3,9 @@
# ===========================================================================
# Packages essential to this app. Needed by anyone who wants to use this app.
# ===========================================================================
Django==1.6.5
Pillow==2.5.1
South==1.0
django-libs==1.59.3
django-generic-positions==0.1.6
Sphinx
factory_boy>2.0.0
easy_thumbnails==1.4
simplejson==3.3.0


# ==============================================================
# Packages needed for running the tests. Needed by contributors.
# ==============================================================
nose
django-nose
coverage
django-coverage
flake8==2.2.2
ipdb==0.8
Django==1.7.8
Pillow==3.1.0
django-libs==1.66.12
django-generic-positions==0.1.7
easy_thumbnails==2.3
simplejson==3.8.1
26 changes: 26 additions & 0 deletions runtests.py
@@ -0,0 +1,26 @@
# !/usr/bin/env python
"""
This script is used to run tests, create a coverage report and output the
statistics at the end of the tox run.
To run this script just execute ``tox``
"""
import re

from fabric.api import abort, local
from fabric.colors import green, red


if __name__ == '__main__':
local('flake8 --ignore=E126 --ignore=W391 --statistics'
' --exclude=submodules,south_migrations,migrations,build .')
local('coverage run --source="user_media" manage.py test -v 2'
' --traceback --failfast --settings=user_media.tests.settings'
' --pattern="*_tests.py"')
local('coverage html -d coverage'
' --omit="*__init__*,*/settings/*,*/migrations/*,'
'*/south_migrations/*,*/tests/*,*admin*,*compat*"')
total_line = local('grep -n pc_cov coverage/index.html', capture=True)
percentage = float(re.findall(r'(\d+)%', total_line)[-1])
if percentage < 100:
abort(red('Coverage is {0}%'.format(percentage)))
print(green('Coverage is {0}%'.format(percentage)))
35 changes: 32 additions & 3 deletions setup.py
@@ -1,6 +1,31 @@
# -*- encoding: utf-8 -*-
"""
Python setup file for the user_media app.
In order to register your app at pypi.python.org, create an account at
pypi.python.org and login, then register your new app like so:
python setup.py register
If your name is still free, you can now make your first release but first you
should check if you are uploading the correct files:
python setup.py sdist
Inspect the output thoroughly. There shouldn't be any temp files and if your
app includes staticfiles or templates, make sure that they appear in the list.
If something is wrong, you need to edit MANIFEST.in and run the command again.
If all looks good, you can make your first release:
python setup.py sdist upload
For new releases, you need to bump the version number in
user_media/__init__.py and re-run the above command.
For more information on creating source distributions, see
http://docs.python.org/2/distutils/sourcedist.html
"""
import os
from setuptools import setup, find_packages
import user_media
import user_media as app


dev_requires = [
'flake8',
'mixer',
]


def read(fname):
Expand All @@ -12,14 +37,14 @@ def read(fname):

setup(
name="django-user-media",
version=user_media.__version__,
version=app.__version__,
description=read('DESCRIPTION'),
long_description=read('README.rst'),
license='The MIT License',
platforms=['OS Independent'],
keywords='django, common, reusable, media, files, upload',
author='Martin Brochhaus',
author_email='mbrochh@gmail.com',
author_email='martin.brochhaus@bitmazk.com',
url="https://github.com/bitmazk/django-user-media",
packages=find_packages(),
include_package_data=True,
Expand All @@ -28,5 +53,9 @@ def read(fname):
'django-generic-positions',
'django-libs',
'simplejson',
'easy_thumbnails',
],
extras_require={
'dev': dev_requires,
},
)
11 changes: 11 additions & 0 deletions test_requirements.txt
@@ -0,0 +1,11 @@
coverage<4.0.0
django-coverage
fabric
easy_thumbnails
flake8
ipdb
mixer
mock
tox
django-compat
six
9 changes: 9 additions & 0 deletions tox.ini
@@ -0,0 +1,9 @@
[tox]
envlist = py27-django{17}

[testenv]
usedevelop = True
deps =
django17: Django>=1.7,<1.8
-rtest_requirements.txt
commands = python runtests.py
7 changes: 7 additions & 0 deletions user_media/forms.py
Expand Up @@ -34,9 +34,16 @@ class UserMediaImageFormMixin(object):

def __init__(self, *args, **kwargs):
super(UserMediaImageFormMixin, self).__init__(*args, **kwargs)
try:
initial_image = getattr(
self.instance, self.image_field_name).order_by(
'-id')[0].image
except IndexError:
initial_image = None
self.fields[self.image_field_name] = forms.ImageField(
required=self.require_user_media_image,
label=self.image_label,
initial=initial_image,
)

def _delete_images(self, instance):
Expand Down

0 comments on commit a908614

Please sign in to comment.