Configurazione progetto Django
Codice completo del sito
Codice completo del sito
Creazione ambiente virtuale e installazione pacchetti
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install django pandas numpy yfinance plotly matplotlib djangorestframework
-
Creazione progetto e app principali
django-admin startproject financeadvisor
cd financeadvisor
python manage.py startapp users
python manage.py startapp portfolios
python manage.py startapp market
-
Aggiornamento
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'portfolios',
'market1️⃣ Modello utenti personalizzato (users/models.py)
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
is_consulente = models.BooleanField(default=False)
is_cliente = models.BooleanField(default=True)
telefono = models.CharField(max_length=20, blank=True, null=True)
indirizzo = models.TextField(blank=True, null=True)
def __str__(self):
return self.username
2️⃣ Configurazione settings.py
AUTH_USER_MODEL = 'users.CustomUser'
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'login'
3️⃣ Forms per registrazione (users/forms.py)
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'telefono', 'indirizzo', 'is_consulente', 'is_cliente')
4️⃣ Views per registrazione e dashboard (users/views.py)
from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from .forms import CustomUserCreationForm
def register(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect('dashboard')
else:
form = CustomUserCreationForm()
return render(request, 'users/register.html', {'form': form})
@login_required
def dashboard(request):
return render(request, 'users/dashboard.html')
5️⃣ URL Routing (users/urls.py)
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path('register/', views.register, name='register'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('dashboard/', views.dashboard, name='dashboard'),
]
6️⃣ Template Login (users/templates/users/login.html)
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Accedi</button>
</form>
<p>Non hai un account? <a href="{% url 'register' %}">Registrati</a></p>
7️⃣ Template Registrazione (users/templates/users/register.html)
<h2>Registrazione</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Registrati</button>
</form>
8️⃣ Dashboard area riservata (users/templates/users/dashboard.html)
<h2>Benvenuto, {{ user.username }}</h2>
{% if user.is_consulente %}
<p>Area Consulente: gestione portafogli e clienti</p>
{% elif user.is_cliente %}
<p>Area Cliente: visualizza il tuo portafoglio e analisi finanziaria</p>
{% endif %}
<a href="{% url 'logout' %}">Logout</a>
1️⃣ Modello Portafoglio e Asset (portfolio/models.py)
from django.db import models
from django.conf import settings
class Asset(models.Model):
nome = models.CharField(max_length=100)
simbolo = models.CharField(max_length=10)
tipo = models.CharField(max_length=50, choices=[('azioni','Azioni'), ('bond','Bond'), ('crypto','Crypto'), ('ETF','ETF')])
def __str__(self):
return f"{self.nome} ({self.simbolo})"
class Portfolio(models.Model):
cliente = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
nome_portafoglio = models.CharField(max_length=100)
assets = models.ManyToManyField(Asset, through='PortfolioAsset')
data_creazione = models.DateField(auto_now_add=True)
def __str__(self):
return f"{self.nome_portafoglio} - {self.cliente.username}"
class PortfolioAsset(models.Model):
portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE)
asset = models.ForeignKey(Asset, on_delete=models.CASCADE)
quantita = models.FloatField()
prezzo_acquisto = models.FloatField()
def valore_attuale(self, prezzo_corrente):
return self.quantita * prezzo_corrente
2️⃣ Views di gestione portafogli (portfolio/views.py)
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Portfolio, Asset, PortfolioAsset
import pandas as pd
import plotly.express as px
import yfinance as yf # Libreria per dati finanziari
@login_required
def portfolio_list(request):
portfolios = Portfolio.objects.filter(cliente=request.user)
return render(request, 'portfolio/portfolio_list.html', {'portfolios': portfolios})
@login_required
def portfolio_detail(request, pk):
portfolio = get_object_or_404(Portfolio, pk=pk, cliente=request.user)
assets = PortfolioAsset.objects.filter(portfolio=portfolio)
# Creazione DataFrame per analisi
data = []
for pa in assets:
ticker = yf.Ticker(pa.asset.simbolo)
prezzo_corrente = ticker.history(period="1d")['Close'].iloc[-1]
data.append({
'Asset': pa.asset.nome,
'Quantità': pa.quantita,
'Prezzo Acquisto': pa.prezzo_acquisto,
'Prezzo Attuale': prezzo_corrente,
'Valore Attuale': pa.valore_attuale(prezzo_corrente)
})
df = pd.DataFrame(data)
# Grafico interattivo
fig = px.pie(df, names='Asset', values='Valore Attuale', title='Distribuzione Portafoglio')
grafico_html = fig.to_html(full_html=False)
return render(request, 'portfolio/portfolio_detail.html', {'portfolio': portfolio, 'df': df.to_dict(orient='records'), 'grafico': grafico_html})
3️⃣ URL Routing (portfolio/urls.py)
from django.urls import path
from . import views
urlpatterns = [
path('', views.portfolio_list, name='portfolio_list'),
path('<int:pk>/', views.portfolio_detail, name='portfolio_detail'),
]
4️⃣ Template Lista Portafogli (portfolio/templates/portfolio/portfolio_list.html)
<h2>I tuoi portafogli</h2>
<ul>
{% for p in portfolios %}
<li>
<a href="{% url 'portfolio_detail' p.pk %}">{{ p.nome_portafoglio }}</a>
</li>
{% empty %}
<li>Nessun portafoglio disponibile.</li>
{% endfor %}
</ul>
5️⃣ Template Dettaglio Portafoglio (portfolio/templates/portfolio/portfolio_detail.html)
<h2>Portafoglio: {{ portfolio.nome_portafoglio }}</h2>
<p>Cliente: {{ portfolio.cliente.username }}</p>
<h3>Dettaglio Asset</h3>
<table border="1">
<tr>
<th>Asset</th>
<th>Quantità</th>
<th>Prezzo Acquisto</th>
<th>Prezzo Attuale</th>
<th>Valore Attuale</th>
</tr>
{% for asset in df %}
<tr>
<td>{{ asset.Asset }}</td>
<td>{{ asset.Quantità }}</td>
<td>{{ asset.Prezzo Acquisto }}</td>
<td>{{ asset.Prezzo Attuale }}</td>
<td>{{ asset.Valore Attuale }}</td>
</tr>
{% endfor %}
</table>
<h3>Grafico Distribuzione Portafoglio</h3>
<div>
{{ grafico|safe }}
</div>
✅ Librerie Python principali utilizzate
Django → backend e gestione utenti/portafogli
pandas → analisi dei dati
plotly → grafici interattivi
yfinance → dati finanziari storici e correnti
Celery (opzionale) → aggiornamento dati periodico
1️⃣ Modello dei portafogli
portfolio/models.py
from django.db import models
from django.contrib.auth.models import User
class Portfolio(models.Model):
cliente = models.ForeignKey(User, on_delete=models.CASCADE)
nome_portafoglio = models.CharField(max_length=100)
data_creazione = models.DateField(auto_now_add=True)
def __str__(self):
return f"{self.nome_portafoglio} - {self.cliente.username}"
class Investimento(models.Model):
portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE, related_name='investimenti')
nome_asset = models.CharField(max_length=100)
tipo_asset = models.CharField(max_length=50) # azioni, obbligazioni, ETF, ecc.
quantita = models.FloatField()
valore_unitario = models.FloatField()
data_inserimento = models.DateField(auto_now_add=True)
@property
def valore_totale(self):
return self.quantita * self.valore_unitario
def __str__(self):
return f"{self.nome_asset} ({self.tipo_asset})"
2️⃣ Form per creare portafogli e investimenti
portfolio/forms.py
from django import forms
from .models import Portfolio, Investimento
class PortfolioForm(forms.ModelForm):
class Meta:
model = Portfolio
fields = ['nome_portafoglio']
class InvestimentoForm(forms.ModelForm):
class Meta:
model = Investimento
fields = ['nome_asset', 'tipo_asset', 'quantita', 'valore_unitario']
3️⃣ Views per portafogli e investimenti
portfolio/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Portfolio, Investimento
from .forms import PortfolioForm, InvestimentoForm
@login_required
def crea_portafoglio(request):
if request.method == 'POST':
form = PortfolioForm(request.POST)
if form.is_valid():
portfolio = form.save(commit=False)
portfolio.cliente = request.user
portfolio.save()
return redirect('dashboard')
else:
form = PortfolioForm()
return render(request, 'portfolio/crea_portafoglio.html', {'form': form})
@login_required
def dettaglio_portafoglio(request, portfolio_id):
portfolio = get_object_or_404(Portfolio, id=portfolio_id)
investimenti = portfolio.investimenti.all()
if request.method == 'POST':
form = InvestimentoForm(request.POST)
if form.is_valid():
investimento = form.save(commit=False)
investimento.portfolio = portfolio
investimento.save()
return redirect('dettaglio_portafoglio', portfolio_id=portfolio.id)
else:
form = InvestimentoForm()
return render(request, 'portfolio/dettaglio_portafoglio.html', {
'portfolio': portfolio,
'investimenti': investimenti,
'form': form
})
4️⃣ URL routing
portfolio/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('dashboard/', views.dashboard, name='dashboard'),
path('crea_portafoglio/', views.crea_portafoglio, name='crea_portafoglio'),
path('portafoglio/<int:portfolio_id>/', views.dettaglio_portafoglio, name='dettaglio_portafoglio'),
]
5️⃣ Template per la gestione dei portafogli
crea_portafoglio.html
<h2>Crea Nuovo Portafoglio</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Crea</button>
</form>
<a href="{% url 'dashboard' %}">Torna alla Dashboard</a>
dettaglio_portafoglio.html
<h2>{{ portfolio.nome_portafoglio }}</h2>
<h3>Investimenti</h3>
<ul>
{% for i in investimenti %}
<li>{{ i.nome_asset }} - {{ i.tipo_asset }} - Quantità: {{ i.quantita }} - Valore unitario: {{ i.valore_unitario }} - Totale: {{ i.valore_totale }}</li>
{% empty %}
<li>Nessun investimento presente.</li>
{% endfor %}
</ul>
<h3>Aggiungi nuovo investimento</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Aggiungi</button>
</form>
<a href="{% url 'dashboard' %}">Torna alla Dashboard</a>
1️⃣ Aggiornamento automatico dei dati finanziari
Per aggiornare i prezzi degli asset in tempo reale, possiamo utilizzare API pubbliche (ad esempio Yahoo Finance tramite la libreria yfinance).
portfolio/utils.py
import yfinance as yf
def aggiorna_valori_investimenti(portfolio):
for investimento in portfolio.investimenti.all():
try:
ticker = investimento.nome_asset
dati = yf.Ticker(ticker)
prezzo = dati.history(period="1d")['Close'].iloc[-1]
investimento.valore_unitario = prezzo
investimento.save()
except Exception as e:
print(f"Errore aggiornamento {investimento.nome_asset}: {e}")
2️⃣ Grafici dei portafogli
Usiamo Plotly per grafici interattivi.
portfolio/views.py (aggiunta)
import plotly.express as px
from django.http import JsonResponse
@login_required
def grafico_portafoglio(request, portfolio_id):
portfolio = get_object_or_404(Portfolio, id=portfolio_id)
investimenti = portfolio.investimenti.all()
nomi = [i.nome_asset for i in investimenti]
valori = [i.valore_totale for i in investimenti]
fig = px.pie(names=nomi, values=valori, title=f"Composizione Portafoglio: {portfolio.nome_portafoglio}")
grafico_json = fig.to_json()
return JsonResponse(grafico_json, safe=False)
Template dettaglio_portafoglio.html aggiornato
<h3>Grafico Portafoglio</h3>
<div id="grafico"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
fetch("{% url 'grafico_portafoglio' portfolio.id %}")
.then(response => response.json())
.then(data => {
Plotly.newPlot('grafico', data.data, data.layout);
});
</script>
3️⃣ Report PDF
Utilizziamo WeasyPrint per generare PDF dai template HTML.
portfolio/views.py (aggiunta)
from django.template.loader import render_to_string
from django.http import HttpResponse
import weasyprint
@login_required
def report_pdf(request, portfolio_id):
portfolio = get_object_or_404(Portfolio, id=portfolio_id)
investimenti = portfolio.investimenti.all()
html_string = render_to_string('portfolio/report_pdf.html', {
'portfolio': portfolio,
'investimenti': investimenti
})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = f'inline; filename="report_{portfolio.nome_portafoglio}.pdf"'
weasyprint.HTML(string=html_string).write_pdf(response)
return response
Template report_pdf.html
<h2>Report Portafoglio: {{ portfolio.nome_portafoglio }}</h2>
<p>Cliente: {{ portfolio.cliente.username }}</p>
<p>Data: {{ portfolio.data_creazione }}</p>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<th>Asset</th>
<th>Tipo</th>
<th>Quantità</th>
<th>Valore Unitario</th>
<th>Valore Totale</th>
</tr>
{% for i in investimenti %}
<tr>
<td>{{ i.nome_asset }}</td>
<td>{{ i.tipo_asset }}</td>
<td>{{ i.quantita }}</td>
<td>{{ i.valore_unitario }}</td>
<td>{{ i.valore_totale }}</td>
</tr>
{% endfor %}
</table>
4️⃣ Report Excel
Usiamo pandas e openpyxl per esportare dati Excel.
portfolio/views.py (aggiunta)
import pandas as pd
from django.http import HttpResponse
@login_required
def report_excel(request, portfolio_id):
portfolio = get_object_or_404(Portfolio, id=portfolio_id)
investimenti = portfolio.investimenti.all()
data = [{
'Asset': i.nome_asset,
'Tipo': i.tipo_asset,
'Quantità': i.quantita,
'Valore Unitario': i.valore_unitario,
'Valore Totale': i.valore_totale
} for i in investimenti]
df = pd.DataFrame(data)
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = f'attachment; filename=report_{portfolio.nome_portafoglio}.xlsx'
df.to_excel(response, index=False)
return response
5️⃣ URL routing
portfolio/urls.py aggiornato
urlpatterns = [
path('dashboard/', views.dashboard, name='dashboard'),
path('crea_portafoglio/', views.crea_portafoglio, name='crea_portafoglio'),
path('portafoglio/<int:portfolio_id>/', views.dettaglio_portafoglio, name='dettaglio_portafoglio'),
path('portafoglio/<int:portfolio_id>/grafico/', views.grafico_portafoglio, name='grafico_portafoglio'),
path('portafoglio/<int:portfolio_id>/report/pdf/', views.report_pdf, name='report_pdf'),
path('portafoglio/<int:portfolio_id>/report/excel/', views.report_excel, name='report_excel'),
]

Nessun commento:
Posta un commento