├── myproject ├── __init__.py ├── core │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0002_auto_20200505_0338.py │ │ └── 0001_initial.py │ ├── tests.py │ ├── apps.py │ ├── urls.py │ ├── admin.py │ ├── models.py │ ├── views.py │ └── templates │ │ ├── base.html │ │ ├── includes │ │ └── nav.html │ │ └── index.html ├── urls.py ├── wsgi.py └── settings.py ├── requirements.txt ├── contrib └── env_gen.py ├── fix └── products.csv ├── manage.py ├── .gitignore └── README.md /myproject/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myproject/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myproject/core/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /myproject/core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /myproject/core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CoreConfig(AppConfig): 5 | name = 'core' 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dj-database-url==0.5.0 2 | Django==2.2.27 3 | django-extensions==2.2.9 4 | django-widget-tweaks==1.4.8 5 | python-decouple==3.3 6 | pytz==2019.3 7 | six==1.14.0 8 | sqlparse==0.3.1 9 | -------------------------------------------------------------------------------- /myproject/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | from django.contrib import admin 3 | urlpatterns = [ 4 | path('', include('myproject.core.urls', namespace='core')), 5 | path('admin/', admin.site.urls), 6 | ] 7 | -------------------------------------------------------------------------------- /myproject/core/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from myproject.core import views as v 3 | 4 | 5 | app_name = 'core' 6 | 7 | 8 | urlpatterns = [ 9 | path('', v.index, name='index'), 10 | path('api/products/', v.products, name='products'), 11 | path('api/categories/', v.categories, name='categories'), 12 | ] 13 | -------------------------------------------------------------------------------- /myproject/core/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Category, Product 3 | 4 | 5 | @admin.register(Product) 6 | class ProductAdmin(admin.ModelAdmin): 7 | list_display = ('__str__', 'category',) 8 | search_fields = ('title',) 9 | list_filter = ('category',) 10 | 11 | 12 | admin.site.register(Category) 13 | -------------------------------------------------------------------------------- /myproject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for myproject project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /contrib/env_gen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django SECRET_KEY generator. 3 | """ 4 | from django.utils.crypto import get_random_string 5 | 6 | 7 | chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' 8 | 9 | CONFIG_STRING = """ 10 | DEBUG=True 11 | SECRET_KEY=%s 12 | ALLOWED_HOSTS=127.0.0.1, .localhost 13 | """.strip() % get_random_string(50, chars) 14 | 15 | # Writing our configuration file to '.env' 16 | with open('.env', 'w') as configfile: 17 | configfile.write(CONFIG_STRING) 18 | -------------------------------------------------------------------------------- /fix/products.csv: -------------------------------------------------------------------------------- 1 | title,price,category 2 | suco de laranja,6,Bebida 3 | refrigerante,5.5,Bebida 4 | água mineral sem gás,4.5,Bebida 5 | pudim de leite,4,Sobremesa 6 | gelatina,1.5,Sobremesa 7 | ambrosia,5,Sobremesa 8 | X-salada,7,Lanche 9 | X-bacon,7,Lanche 10 | X-egg,6,Lanche 11 | X-tudo,10,Lanche 12 | banana,3,Fruta 13 | manga,3,Fruta 14 | melancia,5,Fruta 15 | uva,5,Fruta 16 | morango,5,Fruta 17 | picadinho,15,Refeição 18 | bife com ovo,15,Refeição 19 | frango ao molho,15,Refeição 20 | frango assado,17,Refeição 21 | costela cozida,20,Refeição 22 | costela assada,22,Refeição 23 | prato light,20,Refeição 24 | -------------------------------------------------------------------------------- /myproject/core/migrations/0002_auto_20200505_0338.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.12 on 2020-05-05 03:38 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('core', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='product', 16 | name='category', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='categories', to='core.Category', verbose_name='categoria'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /myproject/core/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Category(models.Model): 5 | title = models.CharField('categoria', max_length=50, unique=True) 6 | 7 | class Meta: 8 | verbose_name = 'categoria' 9 | verbose_name_plural = 'categorias' 10 | 11 | def __str__(self): 12 | return self.title 13 | 14 | 15 | class Product(models.Model): 16 | title = models.CharField('título', max_length=100, unique=True) 17 | price = models.DecimalField('preço', max_digits=8, decimal_places=2) 18 | category = models.ForeignKey( 19 | Category, 20 | verbose_name='categoria', 21 | related_name='categories', 22 | on_delete=models.SET_NULL, 23 | null=True, 24 | blank=True 25 | ) 26 | 27 | class Meta: 28 | ordering = ('title',) 29 | verbose_name = 'produto' 30 | verbose_name_plural = 'produtos' 31 | 32 | def __str__(self): 33 | return self.title 34 | -------------------------------------------------------------------------------- /myproject/core/views.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | from django.http import JsonResponse 3 | from django.shortcuts import render 4 | from .models import Product 5 | 6 | 7 | def index(request): 8 | template_name = 'index.html' 9 | return render(request, template_name) 10 | 11 | 12 | def products(request): 13 | products = Product.objects.values('title', 'price') 14 | data = { 15 | 'data': [ 16 | { 17 | 'title': item['title'], 18 | 'value': float(item['price']) 19 | } 20 | for item in products 21 | ] 22 | } 23 | return JsonResponse(data) 24 | 25 | 26 | def categories(request): 27 | categories = Product.objects\ 28 | .values('category')\ 29 | .annotate(value=Count('category'))\ 30 | .order_by('category')\ 31 | .values('category__title', 'value') 32 | data = { 33 | 'data': [ 34 | { 35 | 'label': item['category__title'], 36 | 'value': item['value'], 37 | } 38 | for item in categories 39 | ] 40 | } 41 | return JsonResponse(data) 42 | -------------------------------------------------------------------------------- /myproject/core/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Django + Chart.js 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | {% block css %}{% endblock css %} 22 | 23 | 24 | 25 | 26 | 27 | {% include "includes/nav.html" %} 28 | 29 |
30 | {% block content %}{% endblock content %} 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {% block js %}{% endblock js %} 41 | 42 | 43 | -------------------------------------------------------------------------------- /myproject/core/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.12 on 2020-05-05 02:21 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Category', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('title', models.CharField(max_length=50, unique=True, verbose_name='categoria')), 20 | ], 21 | options={ 22 | 'verbose_name': 'categoria', 23 | 'verbose_name_plural': 'categorias', 24 | }, 25 | ), 26 | migrations.CreateModel( 27 | name='Product', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('title', models.CharField(max_length=100, unique=True, verbose_name='título')), 31 | ('price', models.DecimalField(decimal_places=2, max_digits=8, verbose_name='preço')), 32 | ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.Category', verbose_name='categoria')), 33 | ], 34 | options={ 35 | 'verbose_name': 'produto', 36 | 'verbose_name_plural': 'produtos', 37 | 'ordering': ('title',), 38 | }, 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /myproject/core/templates/includes/nav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | *.sqlite 132 | *.sqlite3 133 | *.env 134 | *.DS_Store 135 | .venv/ 136 | staticfiles/ 137 | .ipynb_checkpoints/ 138 | -------------------------------------------------------------------------------- /myproject/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for myproject project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.12. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | 13 | import os 14 | from decouple import config, Csv 15 | from dj_database_url import parse as dburl 16 | 17 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 18 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 19 | 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = config('SECRET_KEY') 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = config('DEBUG', default=False, cast=bool) 29 | 30 | ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv()) 31 | 32 | 33 | # Application definition 34 | 35 | INSTALLED_APPS = [ 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | 'django_extensions', 43 | 'myproject.core' 44 | ] 45 | 46 | MIDDLEWARE = [ 47 | 'django.middleware.security.SecurityMiddleware', 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 54 | ] 55 | 56 | ROOT_URLCONF = 'myproject.urls' 57 | 58 | TEMPLATES = [ 59 | { 60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 61 | 'DIRS': [], 62 | 'APP_DIRS': True, 63 | 'OPTIONS': { 64 | 'context_processors': [ 65 | 'django.template.context_processors.debug', 66 | 'django.template.context_processors.request', 67 | 'django.contrib.auth.context_processors.auth', 68 | 'django.contrib.messages.context_processors.messages', 69 | ], 70 | }, 71 | }, 72 | ] 73 | 74 | WSGI_APPLICATION = 'myproject.wsgi.application' 75 | 76 | 77 | # Database 78 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 79 | 80 | default_dburl = 'sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3') 81 | DATABASES = { 82 | 'default': config('DATABASE_URL', default=default_dburl, cast=dburl), 83 | } 84 | 85 | 86 | # Password validation 87 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators 88 | 89 | AUTH_PASSWORD_VALIDATORS = [ 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 101 | }, 102 | ] 103 | 104 | 105 | # Internationalization 106 | # https://docs.djangoproject.com/en/2.2/topics/i18n/ 107 | 108 | LANGUAGE_CODE = 'en-us' 109 | 110 | TIME_ZONE = 'UTC' 111 | 112 | USE_I18N = True 113 | 114 | USE_L10N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 121 | 122 | STATIC_URL = '/static/' 123 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 124 | -------------------------------------------------------------------------------- /myproject/core/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block content %} 3 | 4 | 17 |
18 |

Chart.js

19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 | {% endblock content %} 45 | {% block js %} 46 | 333 | {% endblock js %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # django-chartjs 2 | 3 | Django and ChartJS experiments. 4 | 5 | ## This project was done with: 6 | 7 | * Python 3.8.2 8 | * Django 2.2.12 9 | * Bootstrap 4.0 10 | * ChartJS 2.9.3 11 | 12 | 13 | ## How to run project? 14 | 15 | * Clone this repository. 16 | * Create virtualenv with Python 3. 17 | * Active the virtualenv. 18 | * Install dependences. 19 | * Run the migrations. 20 | 21 | ``` 22 | git clone https://github.com/rg3915/django-chartjs.git 23 | cd django-chartjs 24 | python -m venv .venv 25 | source .venv/bin/activate 26 | pip install -r requirements.txt 27 | python contrib/env_gen.py 28 | python manage.py migrate 29 | ``` 30 | 31 | ## Este projeto foi feito com: 32 | 33 | * Python 3.8.2 34 | * Django 2.2.12 35 | * Bootstrap 4.0 36 | * ChartJS 2.9.3 37 | 38 | ## Como rodar o projeto? 39 | 40 | * Clone esse repositório. 41 | * Crie um virtualenv com Python 3. 42 | * Ative o virtualenv. 43 | * Instale as dependências. 44 | * Rode as migrações. 45 | 46 | ``` 47 | git clone https://github.com/rg3915/django-chartjs.git 48 | cd django-chartjs 49 | python3 -m venv .venv 50 | source .venv/bin/activate 51 | pip install -r requirements.txt 52 | python contrib/env_gen.py 53 | python manage.py migrate 54 | ``` 55 | 56 | ## Criando o projeto do zero 57 | 58 | Baixe este boilerplate. 59 | 60 | ``` 61 | wget https://gist.githubusercontent.com/rg3915/b363f5c4a998f42901705b23ccf4b8e8/raw/39caa9f63aa693ed651cebd4bb503cebffc51f6d/boilerplatesimple.sh 62 | ``` 63 | 64 | Ele serve pra criar um projeto simples em Django com o settings pré-configurado. 65 | 66 | ``` 67 | source boilerplatesimple.sh 68 | ``` 69 | 70 | Após terminar o processo de instalação você pode deletar isso. 71 | 72 | ``` 73 | rm boilerplatesimple.sh 74 | ``` 75 | 76 | ## Chart.js 77 | 78 | O Chart.js é uma biblioteca Javascript para gerar gráficos. 79 | 80 | Clicando em Get Started temos o seguinte exemplo: 81 | 82 | ```javascript 83 | 84 | 123 | ``` 124 | 125 | ### Criando os templates 126 | 127 | Para ver este exemplo funcionando precisamos criar um template: 128 | 129 | ``` 130 | cd myproject/core 131 | mkdir -p templates/includes 132 | ``` 133 | 134 | Vamos um template base. 135 | 136 | ``` 137 | cd templates 138 | wget https://gist.githubusercontent.com/rg3915/0144a2408ec54c4e8008999631c64a30/raw/be05f2f8a483c6ddab3705c13bff0ac5fc2223be/base.html 139 | wget https://gist.githubusercontent.com/rg3915/0144a2408ec54c4e8008999631c64a30/raw/ecbd782e23b3886ce64b318ef5ea194ed89b8ab3/index.html# 140 | 141 | # Vá para a subpasta includes 142 | wget https://gist.githubusercontent.com/rg3915/0144a2408ec54c4e8008999631c64a30/raw/ee78c798ed1fd57e2ba7328342ac3f4ab20268be/nav.html 143 | ``` 144 | 145 | ### Criando views e url. 146 | 147 | Vamos criar a url 148 | 149 | ``` 150 | # core/urls.py 151 | from django.urls import path 152 | from myproject.core import views as v 153 | 154 | 155 | app_name = 'core' 156 | 157 | 158 | urlpatterns = [ 159 | path('', v.index, name='index'), 160 | ] 161 | ``` 162 | 163 | E a views.py 164 | 165 | ``` 166 | from django.shortcuts import render 167 | 168 | 169 | def index(request): 170 | template_name = 'index.html' 171 | return render(request, template_name) 172 | ``` 173 | 174 | ### Rodando a aplicação 175 | 176 | Antes de rodar, faça 177 | 178 | ``` 179 | # Vá para a pasta onde está o manage.py 180 | cd ../.. 181 | python contrib/env_gen.py 182 | python manage.py migrate 183 | ``` 184 | 185 | E por fim, rode a aplicação. 186 | 187 | ``` 188 | python manage.py runserver 189 | ``` 190 | 191 | ### Inserindo o gráfico 192 | 193 | Vamos copiar o exemplo de Get Started para dentro de index.html. 194 | 195 | Veja o resultado em index.html. 196 | 197 | E em `base.html` acrescente, no final do arquivo 198 | 199 | ``` 200 | ... 201 | 202 | ``` 203 | 204 | # Parte 2 205 | 206 | ## Trabalhando com dados reais 207 | 208 | Vamos trabalhar com dados reais vindos do banco de dados. 209 | 210 | Para isso vamos criar alguns modelos: *product* e *category*. 211 | 212 | ### models.py 213 | 214 | Vamos editar o arquivo `models.py`. 215 | 216 | ``` 217 | cat << EOF > models.py 218 | from django.db import models 219 | 220 | 221 | class Category(models.Model): 222 | title = models.CharField('categoria', max_length=50, unique=True) 223 | 224 | class Meta: 225 | verbose_name = 'categoria' 226 | verbose_name_plural = 'categorias' 227 | 228 | def __str__(self): 229 | return self.title 230 | 231 | 232 | class Product(models.Model): 233 | title = models.CharField('título', max_length=100, unique=True) 234 | price = models.DecimalField('preço', max_digits=8, decimal_places=2) 235 | category = models.ForeignKey( 236 | Category, 237 | verbose_name='categoria', 238 | on_delete=models.SET_NULL, 239 | null=True, 240 | blank=True 241 | ) 242 | 243 | class Meta: 244 | ordering = ('title',) 245 | verbose_name = 'produto' 246 | verbose_name_plural = 'produtos' 247 | 248 | def __str__(self): 249 | return self.title 250 | EOF 251 | ``` 252 | 253 | ### Migrações 254 | 255 | Vamos criar as migrações do banco. 256 | 257 | ``` 258 | python manage.py makemigrations 259 | python manage.py migrate 260 | ``` 261 | 262 | ### Inserindo alguns dados 263 | 264 | Para isso abra o `shell_plus`. 265 | 266 | ``` 267 | python manage.py shell_plus 268 | ``` 269 | 270 | E rode o script a seguir: 271 | 272 | ``` 273 | # Criando as categorias 274 | categories = ('Bebida', 'Sobremesa', 'Lanche', 'Fruta', 'Refeição') 275 | [Category.objects.create(title=category) for category in categories] 276 | 277 | # Criando os produtos 278 | import csv 279 | import io 280 | import urllib.request 281 | from pprint import pprint 282 | 283 | 284 | def csv_online_to_list(url: str) -> list: 285 | ''' 286 | Lê um CSV a partir de uma url. 287 | ''' 288 | url_open = urllib.request.urlopen(url) 289 | reader = csv.DictReader(io.StringIO( 290 | url_open.read().decode('utf-8')), delimiter=',') 291 | csv_data = [line for line in reader] 292 | return csv_data 293 | 294 | 295 | products = csv_online_to_list('https://raw.githubusercontent.com/rg3915/django-chartjs/master/fix/products.csv') 296 | 297 | pprint(products) 298 | 299 | aux = [] 300 | 301 | for product in products: 302 | data = { 303 | 'title': product['title'], 304 | 'price': product['price'] 305 | } 306 | category_title = product.get('category') 307 | category = Category.objects.filter(title=category_title).first() 308 | obj = Product(**data) 309 | if category: 310 | obj = Product(category=category, **data) 311 | aux.append(obj) 312 | 313 | Product.objects.bulk_create(aux) 314 | ``` 315 | 316 | 317 | ### Visualizando os dados no Admin 318 | 319 | Talvez você ainda não tenha criado um super usuário... 320 | 321 | ``` 322 | python manage.py createsuperuser --username="admin" 323 | ``` 324 | 325 | Edite `admin.py` 326 | 327 | ``` 328 | cat << EOF > myproject/core/admin.py 329 | from django.contrib import admin 330 | from .models import Category, Product 331 | 332 | 333 | @admin.register(Product) 334 | class ProductAdmin(admin.ModelAdmin): 335 | list_display = ('__str__', 'category',) 336 | search_fields = ('title',) 337 | list_filter = ('category',) 338 | 339 | 340 | admin.site.register(Category) 341 | EOF 342 | ``` 343 | 344 | ### Pegando os dados do banco para retornar no gráfico 345 | 346 | ``` 347 | cat << EOF > myproject/core/views.py 348 | from django.shortcuts import render 349 | from django.http import JsonResponse 350 | from .models import Product 351 | 352 | 353 | def index(request): 354 | template_name = 'index.html' 355 | return render(request, template_name) 356 | 357 | 358 | def products(request): 359 | products = Product.objects.values('title', 'price') 360 | data = { 361 | 'data': [ 362 | { 363 | 'title': item['title'], 364 | 'value': float(item['price']) 365 | } 366 | for item in products 367 | ] 368 | } 369 | return JsonResponse(data) 370 | EOF 371 | ``` 372 | 373 | ### Editando o template 374 | 375 | TODO 376 | 377 | 378 | ### Gráfico de pizza 379 | 380 | Em inglês este gráfico é chamado de **pie**. 381 | 382 | ``` 383 | # core/urls.py 384 | path('api/categories/', v.categories, name='categories'), 385 | ``` 386 | 387 | ``` 388 | # views.py 389 | from django.db.models import Count 390 | from django.http import JsonResponse 391 | from .models import Product 392 | 393 | # ... 394 | 395 | def categories(request): 396 | categories = Product.objects\ 397 | .values('category')\ 398 | .annotate(value=Count('category'))\ 399 | .order_by('category')\ 400 | .values('category__title', 'value') 401 | data = { 402 | 'data': [ 403 | { 404 | 'label': item['category__title'], 405 | 'value': item['value'], 406 | } 407 | for item in categories 408 | ] 409 | } 410 | return JsonResponse(data) 411 | ``` 412 | 413 | --------------------------------------------------------------------------------