mirror of
https://github.com/Hopiu/django-embed-video.git
synced 2026-05-18 01:21:06 +00:00
add HTML5 audio and video backends
This commit is contained in:
parent
4cbb72a691
commit
5e472afc2a
31 changed files with 291 additions and 107 deletions
|
|
@ -1,2 +1,2 @@
|
|||
[report]
|
||||
[run]
|
||||
include = embed_video/*
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ dist
|
|||
.coverage
|
||||
htmlcov
|
||||
.idea
|
||||
.tox
|
||||
|
|
|
|||
43
.travis.yml
43
.travis.yml
|
|
@ -1,27 +1,20 @@
|
|||
sudo: false
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
cache: pip
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
env:
|
||||
- DJANGO_VERSION=1.5.2
|
||||
- DJANGO_VERSION=1.6.5
|
||||
- DJANGO_VERSION=1.7.0
|
||||
- DJANGO_VERSION=1.8.0
|
||||
- DJANGO_VERSION=1.8.6
|
||||
- DJANGO_VERSION=1.9.4
|
||||
install:
|
||||
- pip install -q Django==$DJANGO_VERSION
|
||||
- pip install coveralls
|
||||
- pip install mock
|
||||
- pip install south
|
||||
- pip install nose
|
||||
- pip install testfixtures
|
||||
script:
|
||||
- python setup.py build
|
||||
- PYTHONHASHSEED=0 python setup.py nosetests --verbosity 2 --with-coverage --cover-tests --cover-erase
|
||||
after_success:
|
||||
- coveralls
|
||||
notifications:
|
||||
email: false
|
||||
- TOXENV=py27-django15
|
||||
- TOXENV=py27-django16
|
||||
- TOXENV=py27-django17
|
||||
- TOXENV=py27-django18
|
||||
- TOXENV=py27-django19
|
||||
- TOXENV=py27-django110
|
||||
- TOXENV=py34-django15
|
||||
- TOXENV=py34-django16
|
||||
- TOXENV=py34-django17
|
||||
- TOXENV=py34-django18
|
||||
- TOXENV=py34-django19
|
||||
- TOXENV=py34-django110
|
||||
install: pip install tox coveralls
|
||||
script: tox
|
||||
after_success: coveralls
|
||||
|
|
|
|||
|
|
@ -3,3 +3,8 @@ include CHANGES.rst
|
|||
include LICENSE
|
||||
|
||||
recursive-include embed_video/templates *.html
|
||||
|
||||
recursive-exclude * __pycache__
|
||||
recursive-exclude * *.py[co]
|
||||
recursive-exclude * *~
|
||||
recursive-exclude * .coverage
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Development
|
||||
Development
|
||||
===========
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,23 +4,22 @@ Testing
|
|||
Requirements
|
||||
------------
|
||||
|
||||
The library needs ``Django`` and ``requests`` and ``nose``, ``mock``,
|
||||
``south`` and ``testfixtures`` libraries to run tests.
|
||||
|
||||
::
|
||||
The library needs a copy of ``Django``, e.g.::
|
||||
|
||||
pip install Django
|
||||
pip install requests
|
||||
pip install nose
|
||||
pip install mock
|
||||
pip install south
|
||||
pip install testfixtures
|
||||
|
||||
And several libraries that can be installed from the root of
|
||||
a source checkout::
|
||||
|
||||
pip install -r embed_video/tests/test-requirements.txt
|
||||
|
||||
It's recommended to make a separate virtual environment where you
|
||||
install these packages.
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
Run tests with this command:
|
||||
Run tests in your virtual environment with this command:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -34,7 +33,13 @@ Run tests with coverage:
|
|||
|
||||
::
|
||||
|
||||
pip install coverage
|
||||
nosetests --with-coverage --cover-package=embed_video
|
||||
|
||||
Use tox if you want to test against all supported Django versions,
|
||||
similar to the Travis build. Install it once::
|
||||
|
||||
pip install tox>=2.0
|
||||
|
||||
Run the tests with::
|
||||
|
||||
tox
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
Example project
|
||||
===============
|
||||
|
||||
For easy start with using django-embed-video, you can take a look at example
|
||||
project. It is located in example_project directory in root of repository.
|
||||
To get started with django-embed-video, you can take a look at the example
|
||||
project. It is located in the ``example_project`` directory in the root of
|
||||
the repository.
|
||||
|
||||
.. include:: ../example_project/README.rst
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ Default sizes are ``tiny`` (420x315), ``small`` (480x360), ``medium`` (640x480),
|
|||
{% video my_video '100% x 50%' %}
|
||||
|
||||
|
||||
It is possible to set backend options via parameters in template tag. It is
|
||||
useful for example to enforce HTTPS protocol or set different query appended
|
||||
It is possible to set backend options via parameters in the template tag. It is
|
||||
useful to enforce HTTPS protocol for example or to set different query appended
|
||||
to url.
|
||||
|
||||
::
|
||||
|
|
@ -73,8 +73,8 @@ to url.
|
|||
|
||||
.. tip::
|
||||
|
||||
You can overwrite default template of embed code located in
|
||||
``templates/embed_video/embed_code.html`` or set own file for custom
|
||||
You can overwrite the default template of the embed code located in
|
||||
``templates/embed_video/embed_code.html`` or use your own file for a custom
|
||||
backend (:py:data:`~embed_video.backends.VideoBackend.template_name`).
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
|
@ -87,7 +87,7 @@ Model examples
|
|||
|
||||
.. highlight:: python
|
||||
|
||||
Using the ``EmbedVideoField`` provides you validation of URLs.
|
||||
Using the ``EmbedVideoField`` provides validation of URLs.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -121,8 +121,8 @@ Use ``AdminVideoMixin`` in ``admin.py``.
|
|||
Custom backends
|
||||
###############
|
||||
|
||||
If you have specific needs and default backends don't suits you, you can write
|
||||
your custom backend.
|
||||
If you have specific needs and the default backend doesn't suit you,
|
||||
you can write a custom backend.
|
||||
|
||||
``my_project/my_app/backends.py``::
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ your custom backend.
|
|||
template_name = 'embed_video/custombackend_embed_code.html' # added in v0.9
|
||||
|
||||
You can also overwrite :py:class:`~embed_video.backends.VideoBackend` methods,
|
||||
if using regular expressions isn't well enough.
|
||||
if using regular expressions isn't good enough.
|
||||
|
||||
``my_project/my_project/settings.py``::
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ if using regular expressions isn't well enough.
|
|||
Low level API examples
|
||||
######################
|
||||
|
||||
You can get instance of :py:class:`~embed_video.backends.VideoBackend` in your
|
||||
You can get an instance of :py:class:`~embed_video.backends.VideoBackend` in your
|
||||
python code thanks to :py:func:`~embed_video.backends.detect_backend`:
|
||||
|
||||
::
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
django-embed-video's documentation
|
||||
==================================
|
||||
|
||||
Django app for easy embeding YouTube and Vimeo videos and music from SoundCloud.
|
||||
Django app for easy embedding YouTube and Vimeo videos and music from SoundCloud.
|
||||
|
||||
Repository is located on GitHub: https://github.com/jazzband/django-embed-video
|
||||
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
|
@ -15,7 +14,7 @@ Repository is located on GitHub: https://github.com/jazzband/django-embed-video
|
|||
examples
|
||||
example-project
|
||||
|
||||
development/index
|
||||
development/index
|
||||
|
||||
websites
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ Library API
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api/index
|
||||
api/index
|
||||
|
||||
|
||||
|
||||
|
|
@ -37,4 +36,3 @@ Indices and tables
|
|||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ Installation & Setup
|
|||
Installation
|
||||
############
|
||||
|
||||
The simpliest way is to use pip to install package:
|
||||
The simpliest way is to use pip to install the package:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install django-embed-video
|
||||
|
||||
|
||||
If you want latest version, you may use Git. It is fresh, but unstable.
|
||||
If you want the latest version, you may use Git. It is fresh, but unstable.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
|
@ -28,12 +28,13 @@ settings.
|
|||
|
||||
INSTALLED_APPS = (
|
||||
...
|
||||
|
||||
|
||||
'embed_video',
|
||||
)
|
||||
|
||||
To detect HTTP/S you must use :py:class:`~django.core.context_processors.request`
|
||||
context processor:
|
||||
To detect HTTP/S you must add the :py:class:`~django.template.context_processors.request`
|
||||
(or :py:class:`~django.core.context_processors.request` for Django < 1.9) context
|
||||
processor:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class AdminVideoWidget(forms.TextInput):
|
|||
|
||||
.. todo::
|
||||
|
||||
Django 1.6 provides better parent for this widget -
|
||||
Django 1.6 provides a better parent for this widget -
|
||||
:py:class:`django.forms.URLInput`.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -19,17 +19,23 @@ from .settings import EMBED_VIDEO_BACKENDS, EMBED_VIDEO_TIMEOUT, \
|
|||
|
||||
|
||||
class EmbedVideoException(Exception):
|
||||
""" Parental class for all embed_video exceptions """
|
||||
"""
|
||||
Parental class for all embed_video exceptions.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class VideoDoesntExistException(EmbedVideoException):
|
||||
""" Exception thrown if video doesn't exist """
|
||||
"""
|
||||
Exception thrown if video doesn't exist.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class UnknownBackendException(EmbedVideoException):
|
||||
""" Exception thrown if video backend is not recognized. """
|
||||
"""
|
||||
Exception thrown if video backend is not recognized.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -53,7 +59,6 @@ def detect_backend(url):
|
|||
:return: Returns recognized VideoBackend
|
||||
:rtype: VideoBackend
|
||||
"""
|
||||
|
||||
for backend_name in EMBED_VIDEO_BACKENDS:
|
||||
backend = import_by_path(backend_name)
|
||||
if backend.is_valid(url):
|
||||
|
|
@ -97,7 +102,7 @@ class VideoBackend(object):
|
|||
|
||||
re_detect = None
|
||||
"""
|
||||
Compilede regec (:py:func:`re.compile`) to detect, if input URL is valid
|
||||
Compiled regex (:py:func:`re.compile`) to detect, if input URL is valid
|
||||
for current backend.
|
||||
|
||||
Example: ``re.compile(r'^http://myvideo\.com/.*')``
|
||||
|
|
@ -140,7 +145,7 @@ class VideoBackend(object):
|
|||
|
||||
default_query = ''
|
||||
"""
|
||||
Default query string or `QueryDict` appended to url
|
||||
Default query string or ``QueryDict`` appended to url.
|
||||
|
||||
:type: str
|
||||
"""
|
||||
|
|
@ -154,7 +159,7 @@ class VideoBackend(object):
|
|||
|
||||
def __init__(self, url):
|
||||
"""
|
||||
First it tries to load data from cache and if it don't succeed, run
|
||||
First it tries to load data from cache and if it doesn't succeed, run
|
||||
:py:meth:`init` and then save it to cache.
|
||||
|
||||
:type url: str
|
||||
|
|
@ -201,7 +206,7 @@ class VideoBackend(object):
|
|||
@property
|
||||
def query(self):
|
||||
"""
|
||||
String transformed to QueryDict appended to url.
|
||||
String transformed to ``QueryDict`` appended to url.
|
||||
"""
|
||||
return self._query
|
||||
|
||||
|
|
@ -218,7 +223,7 @@ class VideoBackend(object):
|
|||
def is_valid(cls, url):
|
||||
"""
|
||||
Class method to control if passed url is valid for current backend. By
|
||||
default it is done by :py:data:`re_detect` regex.
|
||||
default this is done using the :py:data:`re_detect` regex.
|
||||
|
||||
:type url: str
|
||||
"""
|
||||
|
|
@ -280,6 +285,75 @@ class VideoBackend(object):
|
|||
setattr(self, key, options[key])
|
||||
|
||||
|
||||
class Html5Backend(VideoBackend):
|
||||
"""
|
||||
Backend for HTML5 media.
|
||||
"""
|
||||
def get_url(self):
|
||||
"""
|
||||
Returns URL.
|
||||
"""
|
||||
return self._url
|
||||
|
||||
def get_code(self):
|
||||
"""
|
||||
Returns video code.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return None
|
||||
|
||||
def get_thumbnail_url(self):
|
||||
"""
|
||||
Returns thumbnail URL.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
class Html5VideoBackend(Html5Backend):
|
||||
"""
|
||||
Backend for HTML5 video.
|
||||
"""
|
||||
template_name = 'embed_video/html5_video.html'
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, url):
|
||||
"""
|
||||
Class method to control if passed url is valid for current backend.
|
||||
|
||||
:type url: str
|
||||
"""
|
||||
try:
|
||||
r = requests.head(url, timeout=EMBED_VIDEO_TIMEOUT)
|
||||
except:
|
||||
raise VideoDoesntExistException()
|
||||
|
||||
return r.headers.get('content-type').startswith('video')
|
||||
|
||||
|
||||
class Html5AudioBackend(Html5Backend):
|
||||
"""
|
||||
Backend for HTML5 audio.
|
||||
"""
|
||||
template_name = 'embed_video/html5_audio.html'
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, url):
|
||||
"""
|
||||
Class method to control if passed url is valid for current backend.
|
||||
|
||||
:type url: str
|
||||
"""
|
||||
try:
|
||||
r = requests.head(url, timeout=EMBED_VIDEO_TIMEOUT)
|
||||
except:
|
||||
raise VideoDoesntExistException()
|
||||
|
||||
return r.headers.get('content-type').startswith('audio')
|
||||
|
||||
|
||||
class YoutubeBackend(VideoBackend):
|
||||
"""
|
||||
Backend for YouTube URLs.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class EmbedVideoField(models.URLField):
|
|||
|
||||
class EmbedVideoFormField(forms.URLField):
|
||||
"""
|
||||
Form field for embeded video. Descendant of
|
||||
Form field for embedded video. Descendant of
|
||||
:py:class:`django.forms.URLField`
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ EMBED_VIDEO_BACKENDS = getattr(settings, 'EMBED_VIDEO_BACKENDS', (
|
|||
'embed_video.backends.VimeoBackend',
|
||||
'embed_video.backends.WistiaBackend',
|
||||
'embed_video.backends.SoundCloudBackend',
|
||||
'embed_video.backends.Html5VideoBackend',
|
||||
'embed_video.backends.Html5AudioBackend',
|
||||
))
|
||||
""" :type: tuple[str] """
|
||||
|
||||
|
|
|
|||
1
embed_video/templates/embed_video/html5_audio.html
Normal file
1
embed_video/templates/embed_video/html5_audio.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<audio src="{{ backend.url }}" controls></audio>
|
||||
1
embed_video/templates/embed_video/html5_video.html
Normal file
1
embed_video/templates/embed_video/html5_video.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<video width="{{ width }}" height="{{ height }}" src="{{ backend.url }}" controls></video>
|
||||
28
embed_video/tests/backends/tests_html5backend.py
Normal file
28
embed_video/tests/backends/tests_html5backend.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
from unittest import TestCase
|
||||
|
||||
from . import BackendTestMixin
|
||||
from embed_video import backends
|
||||
|
||||
|
||||
class HTML5BackendTestCase(TestCase):
|
||||
def test_url(self):
|
||||
url = 'https://collab-project.github.io/videojs-wavesurfer/examples/media/heres_johnny.wav'
|
||||
backend = backends.detect_backend(url)
|
||||
self.assertEqual(backend.get_url(), url)
|
||||
|
||||
|
||||
class Html5VideoBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4', None),
|
||||
('https://collab-project.github.io/videojs-wavesurfer/examples/media/example.mp4', None),
|
||||
)
|
||||
|
||||
instance = backends.Html5VideoBackend
|
||||
|
||||
|
||||
class Html5AudioBackendTestCase(BackendTestMixin, TestCase):
|
||||
urls = (
|
||||
('https://collab-project.github.io/videojs-wavesurfer/examples/media/heres_johnny.wav', None),
|
||||
)
|
||||
|
||||
instance = backends.Html5AudioBackend
|
||||
|
|
@ -20,6 +20,8 @@ EMBED_VIDEO_BACKENDS = (
|
|||
'embed_video.backends.VimeoBackend',
|
||||
'embed_video.backends.WistiaBackend',
|
||||
'embed_video.backends.SoundCloudBackend',
|
||||
'embed_video.backends.Html5VideoBackend',
|
||||
'embed_video.backends.Html5AudioBackend',
|
||||
'embed_video.tests.backends.tests_custom_backend.CustomBackend',
|
||||
)
|
||||
|
||||
|
|
|
|||
7
embed_video/tests/test-requirements.txt
Normal file
7
embed_video/tests/test-requirements.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
requests
|
||||
nose
|
||||
mock
|
||||
south
|
||||
testfixtures
|
||||
coverage
|
||||
flake8
|
||||
|
|
@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
def import_by_path(dotted_path, error_prefix=''):
|
||||
"""
|
||||
Import a dotted module path and return the attribute/class designated by
|
||||
the last name in the path. Raise ImproperlyConfigured if something goes
|
||||
the last name in the path. Raise ``ImproperlyConfigured`` if something goes
|
||||
wrong.
|
||||
|
||||
.. warning::
|
||||
|
|
|
|||
|
|
@ -8,18 +8,21 @@ Running example project
|
|||
|
||||
#. Create database::
|
||||
|
||||
python manage.py syncdb --noinput
|
||||
python manage.py migrate --noinput
|
||||
|
||||
#. And superuser::
|
||||
|
||||
python manage.py createsuperuser
|
||||
|
||||
#. Run testing server::
|
||||
|
||||
python manage.py runserver
|
||||
|
||||
#. Take a look at http://localhost:8000 . You can log in to administration with username ``admin``
|
||||
and password ``admin``.
|
||||
#. Create new posts at http://localhost:8000/admin/ and view them on http://localhost:8000.
|
||||
|
||||
|
||||
Testing HTTPS
|
||||
*************
|
||||
|
||||
To test HTTPS on development server, `follow this instructions
|
||||
To test HTTPS on a development server, `follow these instructions
|
||||
<http://www.ianlewis.org/en/testing-https-djangos-development-server>`_.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
# Django settings for example_project project.
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
|
|
@ -14,24 +13,37 @@ SITE_ID = 1
|
|||
|
||||
SECRET_KEY = 'u%38dln@$1!7w#cxi4np504^sa3_skv5aekad)jy_u0v2mc+nr'
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
'django.core.context_processors.static',
|
||||
'django.core.context_processors.tz',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.core.context_processors.request',
|
||||
)
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
|
||||
APPEND_SLASH = True
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'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',
|
||||
]
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'example_project.wsgi.application'
|
||||
|
||||
ROOT_URLCONF = 'example_project.urls'
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
|
@ -42,6 +54,7 @@ DJANGO_APPS = (
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.admin',
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<title>django-embed-video example project</title>
|
||||
|
||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
font-size: 32px;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = staticfiles_urlpatterns() \
|
||||
+ patterns('',
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^', include('posts.urls', namespace='posts')),
|
||||
)
|
||||
urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^', include('posts.urls', namespace='posts')),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings")
|
|||
# This application object is used by any WSGI server configured to use this
|
||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||
# setting points here.
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.core.wsgi import get_wsgi_application # noqa
|
||||
application = get_wsgi_application()
|
||||
|
||||
# Apply WSGI middleware here.
|
||||
|
|
|
|||
25
example_project/posts/migrations/0001_initial.py
Normal file
25
example_project/posts/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.5 on 2016-04-14 13:17
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import embed_video.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Post',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=50)),
|
||||
('video', embed_video.fields.EmbedVideoField(help_text=b'Link to a YouTube, Soundcloud or Vimeo clip.', verbose_name=b'My media link')),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
example_project/posts/migrations/__init__.py
Normal file
0
example_project/posts/migrations/__init__.py
Normal file
|
|
@ -6,8 +6,10 @@ from embed_video.fields import EmbedVideoField
|
|||
|
||||
class Post(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
video = EmbedVideoField(verbose_name='My video',
|
||||
help_text='This is a help text')
|
||||
video = EmbedVideoField(
|
||||
verbose_name='My media link',
|
||||
help_text='Link to a YouTube, Soundcloud or Vimeo clip.'
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
from django.conf.urls import patterns, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import PostListView, PostDetailView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
urlpatterns = [
|
||||
url(r'(?P<pk>\d+)/$', PostDetailView.as_view(), name='detail'),
|
||||
url(r'$', PostListView.as_view(), name='list'),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
3
setup.cfg
Normal file
3
setup.cfg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[flake8]
|
||||
ignore = E121, E122, E123, E125, E126, E128
|
||||
exclude = docs/*, embed_video/tests/*
|
||||
22
tox.ini
Normal file
22
tox.ini
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[tox]
|
||||
envlist = {py27,py34}-django{15,16,17,18,19,110}
|
||||
|
||||
[testenv]
|
||||
basepython =
|
||||
py27: python2.7
|
||||
py34: python3.4
|
||||
usedevelop = true
|
||||
setenv =
|
||||
DJANGO_SETTINGS_MODULE = embed_video.tests.django_settings
|
||||
PYTHONPATH = {toxinidir}
|
||||
PYTHONHASHSEED = 0
|
||||
passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH
|
||||
deps =
|
||||
-r{toxinidir}/embed_video/tests/test-requirements.txt
|
||||
django15: Django>=1.5,<1.6
|
||||
django16: Django>=1.6,<1.7
|
||||
django17: Django>=1.7,<1.8
|
||||
django18: Django>=1.8,<1.9
|
||||
django19: Django>=1.9,<1.10
|
||||
django110: Django>=1.10,<1.11
|
||||
commands = nosetests -sv --with-coverage --cover-package=embed_video
|
||||
Loading…
Reference in a new issue