tradingview / charting-library-examples

Examples of Charting Library integrations with other libraries, frameworks and data transports
MIT License
1.33k stars 744 forks source link

where to put charting_library and datafeeds folders in django #85

Open Etienneelef opened 5 years ago

Etienneelef commented 5 years ago

Hi,

I have a django app and i don't really know where to put these files in my app. Currently it is in project/app/static/js.

But i have a 404 when i start the python server: GET http://localhost:8000/assets/charting_library/static/en-tv-chart.aa0061904b783ada8056.html 404 (Not Found)

The thing is, i don't have any assets folder so i don't understand why it looks for the file there.

timocov commented 5 years ago

Hi,

can you provide more information for your problem? It would be great if you provide minimal example of repro (please make sure that that example doesn't have charting library's code).

Etienneelef commented 5 years ago

I can provide the structure of my django project :

- project_name
    - app_name
        - locale
        - static
            - css
            - images
            - js
                - wallet.js
                - market.js
        - templates
        apps.py
        backend.py
        cognito.py
        custom_storage.py
        tests.py
        urls.py
        views.py
    - project_name
        __init__.py
        settings.py
        urls.py
        wsgi.py
    .gitignore
    manage.py
    requirements.txt

I can also provide my settings.py :

import os
from django.utils.translation import ugettext_lazy as _
import boto3

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

LOCALE_PATH = (
    os.path.join(BASE_DIR, '/********/locale'),
)

# Quick-start development settings - unsuitable for production

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ********'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']

# AWS COGNITO
AUTHENTICATION_BACKENDS = [
    'django_warrant.backend.CognitoBackend',
]

COGNITO_USER_POOL_ID = '********'
COGNITO_APP_ID = '********'

COGNITO_ATTR_MAPPING = [
    {
        'email': 'email',
        'phone_number': 'phone_number',
    }
]

LOGIN_REDIRECT_URL = '********'

# AWS CloudFront
AWS_S3_REGION_NAME = 'us-east-2'  
AWS_ACCESS_KEY_ID = '********'
AWS_SECRET_ACCESS_KEY = '********'
AWS_S3_HOST = '********'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=1209600, no-transform'
}

# static
BUCKET_STATIC_NAME = '********-static'
CLOUDFRONT_STATIC_DOMAIN = '********.cloudfront.net'

# media
BUCKET_MEDIA_NAME = '********-media'
CLOUDFRONT_MEDIA_DOMAIN = '********.cloudfront.net'

# storage
DEFAULT_FILE_STORAGE = '********.custom_storage.MediaS3BotoStorage'
STATICFILES_STORAGE = '********.custom_storage.CachedStaticS3BotoStorage'

MEDIA_URL = 'https://%s/' % CLOUDFRONT_MEDIA_DOMAIN

AWS_DEFAULT_ACL = None

# Static files (CSS, JavaScript, Images)

STATIC_URL = 'https://%s/' % CLOUDFRONT_STATIC_DOMAIN
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    '********',
    'django_extensions',
    'storages',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = '********.urls'

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',
                'django.template.context_processors.i18n',
            ],
        },
    },
]

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

WSGI_APPLICATION = '********.wsgi.application'

# Database

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Password validation

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization

LANGUAGES = (
    ('fr', _('French')),
    ('en', _('English')),
)

LANGUAGE_CODE = 'fr'

TIME_ZONE = 'Europe/Paris'

USE_I18N = True

USE_L10N = True

USE_TZ = True

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ]
}

I hope it's enough :)

Etienneelef commented 5 years ago

Hello,

Can you provide an answer?

timocov commented 5 years ago

I hope it's enough :)

Can you run this code without looking at code of your application? I don't think so, because the structure you provided contains a lot of other files which you don't provide.

Please provide a minimal self-contained repro code/repo (without your specifics or code) which I can just run and start investigate your problem.

Etienneelef commented 5 years ago

The thing is, i think this is all you need. My other files have nothing to do with TV and don't interact with it. I've made some changes in my app structure like so:

- static 
    - charting_library # folder provided by TV with all its content
    - datafeeds # folder provided by TV with all its content 
    market.js
    wallet.js 
    tv-charts-widget-init.js

I can also give you the content of tv-charts-widget-init.js :

function getLanguageFromURL() {
    const regex = new RegExp('[\\?&]lang=([^&#]*)');
    const results = regex.exec(location.search);

    return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' '));
}

TradingView.onready(function() {
    var widget = window.tvWidget = new TradingView.widget({
            symbol: 'AAPL',
            // BEWARE: no trailing slash is expected in feed URL
            // tslint:disable-next-line:no-any
            datafeed: new window.Datafeeds.UDFCompatibleDatafeed('https://demo_feed.tradingview.com'),
            interval: 'D',
            container_id: 'tv_chart_container',
            library_path: '/js/charting_library/',
            locale: getLanguageFromURL() || 'en',
            disabled_features: ['use_localstorage_for_settings'],
            enabled_features: ['study_templates'],
            charts_storage_url: 'https://saveload.tradingview.com',
            charts_storage_api_version: '1.1',
            client_id: 'tradingview.com',
            user_id: 'public_user_id',
            fullscreen: false,
            autosize: false,
            studies_overrides: {},
    });

    widget.onChartReady(() => {
        const button = widget.createButton()
            .attr('title', 'Click to show a notification popup')
            .addClass('apply-common-tooltip')
            .on('click', () => widget.showNoticeDialog({
                title: 'Notification',
                body: 'TradingView Charting Library API works correctly',
                callback: () => {
                    console.log('Noticed!');
                },
            }));

        button[0].innerHTML = 'Check API';
    });
});

I think the error is coming from something related to the library_path. It basically says that it can't find the files. But it's there...

I also provide you a screenshot of the error:

Screenshot 2019-03-17 at 21 49 25

I hope this helps.

timocov commented 5 years ago

What path you use to serve static folder?

Etienneelef commented 5 years ago

I'm using CloudFront (and S3 bucket) to serve static folders. Here is an example of path:

<img src="{% static '/images/pictos/btc-5.png' %}" alt="">

That's why library_path: '/js/charting_library/', should actually be working.

timocov commented 5 years ago

Sorry, but without a repo (not examples of your code, part of configs or so on) with reproducing the problem I'm not able to help you.

Etienneelef commented 5 years ago

I can grant you access to the repo if it's suitable for you

timocov commented 5 years ago

I believe it's unnecessary due security issues (for both sides). Can you just cleanup your repo from your specific code and provide it?

From what path you serve your static folder?

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

Does it mean that your static files are served from /static/ path? If so, I believe that library_path should be library_path: '/static/js/charting_library/',.

Etienneelef commented 5 years ago

What do you mean by specific code?

I've already tried this path and it didn't work unfortunately

timocov commented 5 years ago

What do you mean by specific code?

What you can't share by NDA for example.

Etienneelef commented 5 years ago

Actually, everything you need is in the previous posts. The code has already been cleaned up from specific code. In settings.py all you would need to check are the AWS related settings. Because i'm uploading statics to S3 and CloudFront so maybe it has an effect on TradingView.

timocov commented 5 years ago

You've provide a list of files, but provide content for only one file.

Again, @Etienneelef , please provide a small example (git repo/gist would be awesome) and steps how we can reproduce your problem (step-by-step: install this stuff, cd to this folder, copy that stuff and so on). Please pay attention that we don't familiar with your stack and can don't know some thing you use everyday. Without that information I don't think we can help you.

Etienneelef commented 5 years ago

Hi,

First of all, i've looked into the Rails example as it is the only one example who comes close to Django.

Here is the entire project structure (so you can understand the following):

- project_name
    - app_name
        - locale
        - static
            - css
            - images
            - js
                * wallet.js
                * market.js
                                 * tv-chart-widget-init.js
                                 - charting_library
                                 - datafeeds
        - templates 
                       - elef 
                                  - cognito 
                                  - market
                                         * market.html
                                  - profile
                                  - wallet
        apps.py
        backend.py
        cognito.py
        custom_storage.py
        tests.py
        urls.py
        views.py
    - project_name
        __init__.py
        settings.py
        urls.py
        wsgi.py
    .gitignore
    manage.py
    requirements.txt

From your charting_library repository on github, i grabbed charting_library and datafeeds folders and put them in my django app at:

elef
     - static
           - js

Then, in the Rails example at app/assets/javascripts i grabbed tv-chart-widget-init.js file and put it here in my django app:

elef
     - static
           - js
                - charting_library
                - datafeeds
                * tv-chart-widget-init.js

In templates/elef/market/ market.html, i have linked tv-chart-widget-init.js. In this file, i also added a div container with id='tv_chart_container to match the container_id line in tv-chart-widget-init.js.

In market.html i also added this:

<script src="{% static 'js/charting_library/charting_library.min.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static '/js/datafeeds/udf/dist/bundle.js' %}"></script>
<script type="text/javascript" src="{% static '/js/datafeeds/udf/dist/polyfills.js' %}"></script>

This is what i did. I provided my settings.py earlier just to let you know how my static files are handled. Everytime i add a new static file, i have to python manage.py collectstatic to upload the files in S3 and CloudFront. I think it's important for you to know that.

The error i'm facing seems to be a route error. I didn't add anything to my urls.py.

Here you've got all the things i've done. I hope this helps

jairotunior commented 4 years ago

Hello,

Yesterday I experienced the same issue trying to implement the tradingview charting library with Django.

The issue is inside the _chartinglibrary.min.js, this file create the route (in my case) for the file en-tv-chart.08b1d9ed36065f36316f.html but it does not take into account the route for serving static files that Django implement.

In the settings.py Django defines the next property:

STATIC_URL = '/static/'

This means that all static files are served in the URL: http://localhost:8000/static/ (In local development)

The solution is to add the preffix static/ in the next line of the file _chartinglibrary.min.js.

var e="static/"+(this._options.library_path||"")+"static/"+encodeURIComponent(this._options.locale)+"-tv-chart.08b1d9ed36065f36316f.html#symbol="+encodeURIComponent(this._options.symbol||"")+"&interval="+encodeURIComponent(this._options.interval)+(this._options.timeframe?"&timeframe="+encodeURIComponent(this._options.timeframe):"")+(this._options.toolbar_bg?"&toolbarbg="+encodeURIComponent(this._options.toolbar_bg.replace("#","")):"")+(this._options.studies_access?"&studiesAccess="+encodeURIComponent(JSON.stringify(this._options.studies_access)):"")+"&widgetbar="+encodeURIComponent(JSON.stringify(this._options.widgetbar))+(this._options.drawings_access?"&drawingsAccess="+encodeURIComponent(JSON.stringify(this._options.drawings_access)):"")+"&timeFrames="+encodeURIComponent(JSON.stringify(this._options.time_frames))+"&locale="+encodeURIComponent(this._options.locale)+"&uid="+encodeURIComponent(this._id)+"&clientId="+encodeURIComponent(String(this._options.client_id))+"&userId="+encodeURIComponent(String(this._options.user_id))+(this._options.charts_storage_url?"&chartsStorageUrl="+encodeURIComponent(this._options.charts_storage_url):"")+(this._options.charts_storage_api_version?"&chartsStorageVer="+encodeURIComponent(this._options.charts_storage_api_version):"")+(this._options.custom_css_url?"&customCSS="+encodeURIComponent(this._options.custom_css_url):"")+(this._options.auto_save_delay?"&autoSaveDelay="+encodeURIComponent(String(this._options.auto_save_delay)):"")+"&debug="+encodeURIComponent(String(this._options.debug))+(this._options.snapshot_url?"&snapshotUrl="+encodeURIComponent(this._options.snapshot_url):"")+(this._options.timezone?"&timezone="+encodeURIComponent(this._options.timezone):"")+(this._options.study_count_limit?"&studyCountLimit="+encodeURIComponent(String(this._options.study_count_limit)):"")+(this._options.symbol_search_request_delay?"&ssreqdelay="+encodeURIComponent(String(this._options.symbol_search_request_delay)):"")+(this._options.theme?"&theme="+encodeURIComponent(String(this._options.theme)):"")

In the django documentation explain how to serve static files during the development and production. https://docs.djangoproject.com/en/3.0/howto/static-files/#serving-static-files-during-development

timocov commented 4 years ago

@jairotunior that's what library_path is for.

ashokgaire commented 2 years ago

had a similar issue , you need to provide the exact path from starting from datafeed.js file

for example , if you have.

static

you library path must looks like this. library_path: 'static/charting_library/'

but here's an another use case . let's say you are accessing the widget from path that's look like localhost:8000/charts

then you need to go open directory back like this library_path: '../static/charting_library/'

you have to reach the root path of your url.

then you need to go back 3 steps to react static path and point to charting_library like this library_path: '../../../static/charting_library/'

for this to work , make sure your static_url in settings.py looks like this STATIC_URL = '/static/'