├── .gitignore ├── accounts ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-311.pyc │ ├── admin.cpython-311.pyc │ ├── apps.cpython-311.pyc │ ├── forms.cpython-311.pyc │ ├── models.cpython-311.pyc │ └── views.cpython-311.pyc ├── admin.py ├── apps.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-311.pyc ├── models.py ├── templates │ ├── login.html │ └── register.html ├── tests.py └── views.py ├── app ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-311.pyc │ ├── settings.cpython-311.pyc │ ├── urls.cpython-311.pyc │ └── wsgi.cpython-311.pyc ├── asgi.py ├── settings.py ├── templates │ └── base.html ├── urls.py └── wsgi.py ├── carros_uwsgi.ini ├── cars ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-311.pyc │ ├── admin.cpython-311.pyc │ ├── apps.cpython-311.pyc │ ├── forms.cpython-311.pyc │ ├── models.cpython-311.pyc │ ├── signals.cpython-311.pyc │ └── views.cpython-311.pyc ├── admin.py ├── apps.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_brand_alter_car_brand.py │ ├── 0003_car_photo_car_plate.py │ ├── 0004_carinventory.py │ ├── 0005_car_bio.py │ ├── __init__.py │ └── __pycache__ │ │ ├── 0001_initial.cpython-311.pyc │ │ ├── 0002_brand_alter_car_brand.cpython-311.pyc │ │ ├── 0003_car_photo_car_plate.cpython-311.pyc │ │ ├── 0004_carinventory.cpython-311.pyc │ │ ├── 0005_car_bio.cpython-311.pyc │ │ └── __init__.cpython-311.pyc ├── models.py ├── signals.py ├── templates │ ├── car_delete.html │ ├── car_detail.html │ ├── car_update.html │ ├── cars.html │ └── new_car.html ├── tests.py └── views.py ├── manage.py ├── openai_api ├── __pycache__ │ └── client.cpython-311.pyc └── client.py ├── requirements.txt └── uwsgi_params /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | db.sqlite3 3 | media -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/__pycache__/admin.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/admin.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/__pycache__/apps.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/apps.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/__pycache__/forms.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/forms.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/__pycache__/models.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/models.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/__pycache__/views.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/__pycache__/views.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'accounts' 7 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/migrations/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/accounts/migrations/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /accounts/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 | {% csrf_token %} 6 | 7 | 8 | {{ login_form.as_table }} 9 |
10 | 11 | 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /accounts/templates/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 |
6 | {% csrf_token %} 7 |
8 | {{ user_form.username.errors }} 9 | 10 | {{ user_form.username }} 11 |
12 | 13 |
14 | {{ user_form.password1.errors }} 15 | 16 | {{ user_form.password1 }} 17 |
18 | 19 |
20 | {{ user_form.password2.errors }} 21 | 22 | {{ user_form.password2 }} 23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import UserCreationForm, AuthenticationForm 2 | from django.contrib.auth import authenticate, login, logout 3 | from django.shortcuts import render, redirect 4 | 5 | 6 | def register_view(request): 7 | if request.method == "POST": 8 | user_form = UserCreationForm(request.POST) 9 | if user_form.is_valid(): 10 | user_form.save() 11 | return redirect('login') 12 | else: 13 | user_form = UserCreationForm() 14 | return render(request, 'register.html', {'user_form': user_form}) 15 | 16 | 17 | def login_view(request): 18 | if request.method == "POST": 19 | username = request.POST["username"] 20 | password = request.POST["password"] 21 | user = authenticate(request, username=username, password=password) 22 | if user is not None: 23 | login(request, user) 24 | return redirect('cars_list') 25 | else: 26 | login_form = AuthenticationForm() 27 | else: 28 | login_form = AuthenticationForm() 29 | return render(request, 'login.html', {'login_form': login_form}) 30 | 31 | 32 | def logout_view(request): 33 | logout(request) 34 | return redirect('cars_list') 35 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/app/__init__.py -------------------------------------------------------------------------------- /app/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/app/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /app/__pycache__/settings.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/app/__pycache__/settings.cpython-311.pyc -------------------------------------------------------------------------------- /app/__pycache__/urls.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/app/__pycache__/urls.cpython-311.pyc -------------------------------------------------------------------------------- /app/__pycache__/wsgi.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/app/__pycache__/wsgi.cpython-311.pyc -------------------------------------------------------------------------------- /app/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for app project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /app/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for app project. 3 | 4 | Generated by 'django-admin startproject' using Django 4.1.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/4.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | from pathlib import Path 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'django-insecure-gf9wfc@y-hhyc!-gufza%0jr#%v-80bt8vceoznvvz9k4nu1#c' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = ['*'] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'cars', 42 | 'accounts', 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.messages.middleware.MessageMiddleware', 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | ] 54 | 55 | ROOT_URLCONF = 'app.urls' 56 | 57 | TEMPLATES = [ 58 | { 59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 60 | 'DIRS': ['app/templates'], 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'app.wsgi.application' 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases 78 | 79 | DATABASES = { 80 | 'default': { 81 | 'ENGINE': 'django.db.backends.postgresql', 82 | 'NAME': 'carros', 83 | 'USER': 'postgres', 84 | 'PASSWORD': 'djangomaster', 85 | 'HOST': 'localhost', 86 | 'PORT': '5432', 87 | } 88 | } 89 | 90 | 91 | # Password validation 92 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/4.1/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'pt-br' 114 | 115 | TIME_ZONE = 'America/Sao_Paulo' 116 | 117 | USE_I18N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/4.1/howto/static-files/ 124 | 125 | STATIC_URL = 'static/' 126 | STATIC_ROOT = os.path.join(BASE_DIR, 'static/') 127 | 128 | # Default primary key field type 129 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field 130 | 131 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 132 | 133 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 134 | MEDIA_URL = '/media/' 135 | -------------------------------------------------------------------------------- /app/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 70 | 71 | 72 |
73 | 91 |
92 | 93 |
94 | {% block content %} 95 | {% endblock %} 96 |
97 | 98 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /app/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path 3 | from django.conf import settings 4 | from django.conf.urls.static import static 5 | from cars.views import CarsListView, NewCarCreateView, CarDetailView, CarUpdateView, CarDeleteView 6 | from accounts.views import register_view, login_view, logout_view 7 | 8 | 9 | urlpatterns = [ 10 | path('admin/', admin.site.urls), 11 | path('register/', register_view, name='register'), 12 | path('login/', login_view, name='login'), 13 | path('logout/', logout_view, name='logout'), 14 | path('cars/', CarsListView.as_view(), name='cars_list'), 15 | path('new_car/', NewCarCreateView.as_view(), name='new_car'), 16 | path('car//', CarDetailView.as_view(), name='car_detail'), 17 | path('car//update/', CarUpdateView.as_view(), name='car_update'), 18 | path('car//delete/', CarDeleteView.as_view(), name='car_delete'), 19 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 20 | -------------------------------------------------------------------------------- /app/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for app 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/4.1/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', 'app.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /carros_uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | 3 | chdir = /var/www/carros 4 | module = app.wsgi 5 | home = /var/www/carros/venv 6 | master = true 7 | processes = 10 8 | socket = /var/www/carros/carros.sock 9 | chmod-socket = 666 10 | vacuum = true -------------------------------------------------------------------------------- /cars/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__init__.py -------------------------------------------------------------------------------- /cars/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/admin.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/admin.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/apps.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/apps.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/forms.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/forms.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/models.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/models.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/signals.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/signals.cpython-311.pyc -------------------------------------------------------------------------------- /cars/__pycache__/views.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/__pycache__/views.cpython-311.pyc -------------------------------------------------------------------------------- /cars/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from cars.models import Car, Brand 3 | 4 | 5 | class BrandAdmin(admin.ModelAdmin): 6 | list_display = ('name',) 7 | search_fields = ('name',) 8 | 9 | 10 | class CarAdmin(admin.ModelAdmin): 11 | list_display = ('model', 'brand', 'factory_year', 'model_year', 'value') 12 | search_fields = ('model', 'brand') 13 | 14 | 15 | admin.site.register(Brand, BrandAdmin) 16 | admin.site.register(Car, CarAdmin) 17 | -------------------------------------------------------------------------------- /cars/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CarsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'cars' 7 | 8 | def ready(self): 9 | import cars.signals 10 | -------------------------------------------------------------------------------- /cars/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from cars.models import Car 3 | 4 | 5 | class CarModelForm(forms.ModelForm): 6 | class Meta: 7 | model = Car 8 | fields = '__all__' 9 | 10 | 11 | def clean_value(self): 12 | value = self.cleaned_data.get('value') 13 | if value < 20000: 14 | self.add_error('value', 'Valor mínimo do carro deve ser de R$20.000') 15 | return value 16 | 17 | def clean_factory_year(self): 18 | factory_year = self.cleaned_data.get('factory_year') 19 | if factory_year < 1975: 20 | self.add_error('factory_year', 'Não é possível cadastrar carros fabricados antes de 1975') 21 | return factory_year 22 | -------------------------------------------------------------------------------- /cars/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.6 on 2023-02-12 16:55 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Car', 16 | fields=[ 17 | ('id', models.AutoField(primary_key=True, serialize=False)), 18 | ('model', models.CharField(max_length=200)), 19 | ('brand', models.CharField(max_length=200)), 20 | ('factory_year', models.IntegerField(blank=True, null=True)), 21 | ('model_year', models.IntegerField(blank=True, null=True)), 22 | ('value', models.FloatField(blank=True, null=True)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /cars/migrations/0002_brand_alter_car_brand.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.6 on 2023-02-12 18:06 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 | ('cars', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Brand', 16 | fields=[ 17 | ('id', models.AutoField(primary_key=True, serialize=False)), 18 | ('name', models.CharField(max_length=200)), 19 | ], 20 | ), 21 | migrations.AlterField( 22 | model_name='car', 23 | name='brand', 24 | field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='car_brand', to='cars.brand'), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /cars/migrations/0003_car_photo_car_plate.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.6 on 2023-02-12 18:50 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('cars', '0002_brand_alter_car_brand'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='car', 15 | name='photo', 16 | field=models.ImageField(blank=True, null=True, upload_to='cars/'), 17 | ), 18 | migrations.AddField( 19 | model_name='car', 20 | name='plate', 21 | field=models.CharField(blank=True, max_length=10, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /cars/migrations/0004_carinventory.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.6 on 2023-05-01 17:55 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('cars', '0003_car_photo_car_plate'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='CarInventory', 15 | fields=[ 16 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('cars_count', models.IntegerField()), 18 | ('cars_value', models.FloatField()), 19 | ('created_at', models.DateTimeField(auto_now_add=True)), 20 | ], 21 | options={ 22 | 'ordering': ['-created_at'], 23 | }, 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /cars/migrations/0005_car_bio.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.6 on 2023-05-21 16:40 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('cars', '0004_carinventory'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='car', 15 | name='bio', 16 | field=models.TextField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /cars/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__init__.py -------------------------------------------------------------------------------- /cars/migrations/__pycache__/0001_initial.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/0001_initial.cpython-311.pyc -------------------------------------------------------------------------------- /cars/migrations/__pycache__/0002_brand_alter_car_brand.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/0002_brand_alter_car_brand.cpython-311.pyc -------------------------------------------------------------------------------- /cars/migrations/__pycache__/0003_car_photo_car_plate.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/0003_car_photo_car_plate.cpython-311.pyc -------------------------------------------------------------------------------- /cars/migrations/__pycache__/0004_carinventory.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/0004_carinventory.cpython-311.pyc -------------------------------------------------------------------------------- /cars/migrations/__pycache__/0005_car_bio.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/0005_car_bio.cpython-311.pyc -------------------------------------------------------------------------------- /cars/migrations/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/cars/migrations/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /cars/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Brand(models.Model): 5 | id = models.AutoField(primary_key=True) 6 | name = models.CharField(max_length=200) 7 | 8 | def __str__(self): 9 | return self.name 10 | 11 | 12 | class Car(models.Model): 13 | id = models.AutoField(primary_key=True) 14 | model = models.CharField(max_length=200) 15 | brand = models.ForeignKey(Brand, on_delete=models.PROTECT, related_name='car_brand') 16 | factory_year = models.IntegerField(blank=True, null=True) 17 | model_year = models.IntegerField(blank=True, null=True) 18 | plate = models.CharField(max_length=10, blank=True, null=True) 19 | value = models.FloatField(blank=True, null=True) 20 | photo = models.ImageField(upload_to='cars/', blank=True, null=True) 21 | bio = models.TextField(blank=True, null=True) 22 | 23 | def __str__(self): 24 | return self.model 25 | 26 | 27 | class CarInventory(models.Model): 28 | cars_count = models.IntegerField() 29 | cars_value = models.FloatField() 30 | created_at = models.DateTimeField(auto_now_add=True) 31 | 32 | class Meta: 33 | ordering = ['-created_at'] 34 | 35 | def __str__(self): 36 | return f'{self.cars_count} - {self.cars_value}' 37 | -------------------------------------------------------------------------------- /cars/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import pre_save, post_save, post_delete 2 | from django.db.models import Sum 3 | from django.dispatch import receiver 4 | from cars.models import Car, CarInventory 5 | from openai_api.client import get_car_ai_bio 6 | 7 | 8 | def car_inventory_update(): 9 | cars_count = Car.objects.all().count() 10 | cars_value = Car.objects.aggregate( 11 | total_value=Sum('value') 12 | )['total_value'] 13 | CarInventory.objects.create( 14 | cars_count=cars_count, 15 | cars_value=cars_value 16 | ) 17 | 18 | 19 | @receiver(pre_save, sender=Car) 20 | def car_pre_save(sender, instance, **kwargs): 21 | if not instance.bio: 22 | ai_bio = get_car_ai_bio( 23 | instance.model, instance.brand, instance.model_year 24 | ) 25 | instance.bio = ai_bio 26 | 27 | 28 | @receiver(post_save, sender=Car) 29 | def car_post_save(sender, instance, **kwargs): 30 | car_inventory_update() 31 | 32 | 33 | @receiver(post_delete, sender=Car) 34 | def car_post_delete(sender, instance, **kwargs): 35 | car_inventory_update() 36 | -------------------------------------------------------------------------------- /cars/templates/car_delete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 48 |
49 |
50 |

Deletar Carro

51 |
52 |
53 |

Tem certeza que deseja deletar o carro {{ object.brand }} {{ object.model }}?

54 |
55 | {% csrf_token %} 56 |
57 | 58 | Cancelar 59 |
60 |
61 |
62 |
63 | {% endblock %} 64 | -------------------------------------------------------------------------------- /cars/templates/car_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 82 |
83 | {% if object.photo %} 84 | {{ object.model }} - {{ object.brand }} 85 | {% else %} 86 |

Foto não disponível

87 | {% endif %} 88 |

{{ object.brand }} {{ object.model }}

89 |

Ano de fabricação: {{ object.factory_year }}

90 |

Ano do modelo: {{ object.model_year }}

91 |

Placa: {{ object.plate }}

92 |

Preço: R$ {{ object.value }}

93 | {% if object.bio %} 94 |

Bio: {{ object.bio }}

95 | {% endif %} 96 |
97 | {% if user.is_authenticated %} 98 |
99 | Editar 100 | Deletar 101 |
102 | {% endif %} 103 | {% endblock %} 104 | -------------------------------------------------------------------------------- /cars/templates/car_update.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 | 109 |
110 | {% csrf_token %} 111 |

Editar Carro

112 | 113 | {{ form.as_table }} 114 |
115 |
116 |
117 | 118 | Deletar Carro 119 | Cancelar 120 |
121 |
122 |
123 | {% endblock %} 124 | -------------------------------------------------------------------------------- /cars/templates/cars.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 105 | 106 |
107 | 108 | 109 |
110 | 111 |
112 | {% if cars %} 113 | {% for car in cars %} 114 | 115 |
116 | {% if car.photo %} 117 | {{ car.model }} - {{ car.brand }} 118 | {% else %} 119 |

Foto não disponível

120 | {% endif %} 121 |

{{ car.brand }} {{ car.model }}

122 |

{{ car.factory_year }} - R$ {{ car.value }}

123 |
124 |
125 | {% endfor %} 126 | {% else %} 127 |

Nenhum carro encontrado.

128 | {% endif %} 129 |
130 | {% endblock %} -------------------------------------------------------------------------------- /cars/templates/new_car.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 | {% csrf_token %} 6 | 7 | 8 | {{ form.as_table }} 9 |
10 | 11 | 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /cars/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /cars/views.py: -------------------------------------------------------------------------------- 1 | from cars.models import Car 2 | from cars.forms import CarModelForm 3 | from django.urls import reverse_lazy 4 | from django.contrib.auth.decorators import login_required 5 | from django.utils.decorators import method_decorator 6 | from django.views.generic import ListView, CreateView, DetailView, UpdateView, DeleteView 7 | 8 | 9 | class CarsListView(ListView): 10 | model = Car 11 | template_name = 'cars.html' 12 | context_object_name = 'cars' 13 | 14 | def get_queryset(self): 15 | cars = super().get_queryset().order_by('model') 16 | search = self.request.GET.get('search') 17 | if search: 18 | cars = cars.filter(model__icontains=search) 19 | return cars 20 | 21 | 22 | class CarDetailView(DetailView): 23 | model = Car 24 | template_name = 'car_detail.html' 25 | 26 | 27 | @method_decorator(login_required(login_url='login'), name='dispatch') 28 | class NewCarCreateView(CreateView): 29 | model = Car 30 | form_class = CarModelForm 31 | template_name = 'new_car.html' 32 | success_url = '/cars/' 33 | 34 | 35 | @method_decorator(login_required(login_url='login'), name='dispatch') 36 | class CarUpdateView(UpdateView): 37 | model = Car 38 | form_class = CarModelForm 39 | template_name = 'car_update.html' 40 | 41 | def get_success_url(self): 42 | return reverse_lazy('car_detail', kwargs={'pk': self.object.pk}) 43 | 44 | 45 | @method_decorator(login_required(login_url='login'), name='dispatch') 46 | class CarDeleteView(DeleteView): 47 | model = Car 48 | template_name = 'car_delete.html' 49 | success_url = '/cars/' 50 | -------------------------------------------------------------------------------- /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 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /openai_api/__pycache__/client.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pycodebr/carros/5a6e359a1ed0b3dbbe71f75fe31a906286d8f716/openai_api/__pycache__/client.cpython-311.pyc -------------------------------------------------------------------------------- /openai_api/client.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI 2 | 3 | 4 | client = OpenAI( 5 | api_key='API_KEY' 6 | ) 7 | 8 | 9 | def get_car_ai_bio(model, brand, year): 10 | message = '''' 11 | Me mostre uma descrição de venda para o carro {} {} {} em apenas 250 caracteres. Fale coisas específicas desse modelo. 12 | Descreva especificações técnicas desse modelo de carro. 13 | ''' 14 | message = message.format(brand, model, year) 15 | response = client.chat.completions.create( 16 | messages=[ 17 | { 18 | 'role': 'user', 19 | 'content': message 20 | } 21 | ], 22 | max_tokens=1000, 23 | model='gpt-3.5-turbo', 24 | ) 25 | 26 | return response.choices[0].message.content 27 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.8.4 2 | aiosignal==1.3.1 3 | asgiref==3.6.0 4 | async-timeout==4.0.2 5 | attrs==23.1.0 6 | certifi==2022.12.7 7 | charset-normalizer==3.1.0 8 | colorama==0.4.6 9 | Django==4.1.6 10 | flake8==6.0.0 11 | frozenlist==1.3.3 12 | idna==3.4 13 | mccabe==0.7.0 14 | multidict==6.0.4 15 | openai==0.27.4 16 | Pillow==9.4.0 17 | psycopg2-binary==2.9.6 18 | pycodestyle==2.10.0 19 | pyflakes==3.0.1 20 | requests==2.28.2 21 | sqlparse==0.4.3 22 | tqdm==4.65.0 23 | tzdata==2022.7 24 | urllib3==1.26.15 25 | yarl==1.9.1 26 | -------------------------------------------------------------------------------- /uwsgi_params: -------------------------------------------------------------------------------- 1 | uwsgi_param QUERY_STRING $query_string; 2 | uwsgi_param REQUEST_METHOD $request_method; 3 | uwsgi_param CONTENT_TYPE $content_type; 4 | uwsgi_param CONTENT_LENGTH $content_length; 5 | uwsgi_param REQUEST_URI $request_uri; 6 | uwsgi_param PATH_INFO $document_uri; 7 | uwsgi_param DOCUMENT_ROOT $document_root; 8 | uwsgi_param SERVER_PROTOCOL $server_protocol; 9 | uwsgi_param REQUEST_SCHEME $scheme; 10 | uwsgi_param HTTPS $https if_not_empty; 11 | uwsgi_param REMOTE_ADDR $remote_addr; 12 | uwsgi_param REMOTE_PORT $remote_port; 13 | uwsgi_param SERVER_PORT $server_port; 14 | uwsgi_param SERVER_NAME $server_name; --------------------------------------------------------------------------------