Hello Coders!
Django 是一个用Python构建的强大网络框架,你可以用它来创建功能齐全的网络应用程序或网络API。本文介绍了 ,如何使用step-by-step **Django、Django REST框架和Chart.js**展示三种不同的图表( 、 、 图表)。内容介绍了所有层次和概念(API、JS、Html),还提供了 的链接。pie line bar source code, saved on Github
谢谢你的阅读!内容由
App Generator提供。
-
👉
Setup the Django项目 -
👉 编写
app models -
👉加载
sample data -
👉 对
serializers进行编码 -
👉 编写
API via DRF -
👉 对
Javascript部分进行编码 -
👉 更新
Configuration and routing -
👉通过DRF的Django图表- 源代码
-
👉 更多的Django应用程序和仪表板
✨ 设置项目
在去之前,请确保,首先,让我们来设置项目。请随意使用你最喜欢的python环境管理工具。我在这里会使用virtualenv 。
$ virtualenv env
$ source env/bin/activate
之后,我们安装开发中要用到的库,并创建项目。
$ pip install django
$ pip install djangorestframework
$ pip install djangorestframework-simplejwt
$ pip install django-import-export
创建项目
$ django-admin startproject core
我们首先要创建一个应用程序,它将包含所有项目的具体功能。
$ django-admin startapp apps
创建后,删除所有文件和文件夹,除了__init__.py 、views.py 、models.py 、apps.py 。然后打开包含Django配置的设置文件,在INSTALLED_APPS 中加入core。
# core/settings.py
...
'django.contrib.messages',
'django.contrib.staticfiles',
'apps'
很好!通过运行下面的命令,确保项目已经设置好了。
$ python manage.py makemigrations
$ python manage.py migrate
之后,运行下面的命令来启动服务器。
$ python manage runserver
如果你访问localhost:8000 ,我们应该看到Django默认的闪屏。
✨ 编写模型
这个项目将包含两个模型。
- 用户模型。
- 和产品模型。
按照这个图,我们注意到这些模型有相同的字段,即创建和更新。在为每个功能(用户和产品)创建应用程序之前,让我们创建一个基础模型,它将被用户模型和Product 模型使用。
在apps/models.py中,添加以下内容。
from django.db import models
from django.utils import timezone
class BaseModel(models.Model):
created = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
abstract=True ,确保不会为这个模型产生迁移。让我们转而编写User 模型。
👉用户模型
在编写模型之前,我们需要创建一个Django应用程序。在apps目录下,输入以下命令。
$ django-admin startapp user
完成后,重写apps/user/apps.py 文件。
from django.apps import AppConfig
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.user'
label = 'apps_user'
而我们现在可以在settings.py 文件中注册应用程序。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps', # <-- OLD
'apps.user', # <-- NEW
'import_export',
'rest_framework'
]
现在让我们基于BaseModel类来编写用户模型。
from django.contrib.auth.models import AbstractUser
from django.db import models
from apps.models import BaseModel
class User(AbstractUser, BaseModel):
has_purchased = models.BooleanField(default=False)
Django提供了一个名为AbstractUser的类,它带有以下字段。
username = models.CharField(
_("username"),
max_length=150,
unique=True,
help_text=_(
"Required. 150 characters or fewer."
),
validators=[username_validator],
error_messages={
"unique": _("A user with that username already exists."),
},
)
first_name = models.CharField(_("first name"), max_length=150, blank=True)
last_name = models.CharField(_("last name"), max_length=150, blank=True)
email = models.EmailField(_("email address"), blank=True)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_("Designates whether the user can log into this admin site."),
)
is_active = models.BooleanField(
_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. "
),
)
date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
它对我们这里的需求非常有效。我们还将添加一个新的字段has_purchased ,以追踪在API上至少购买过一次的用户。在运行迁移和提交对数据库的修改之前,让我们在settings.py中为Django将使用的AUTH_USER_MODEL ,添加一个配置。
...
AUTH_USER_MODEL = "apps_user.User"
...
现在运行下面的命令。
$ python manage.py makemigrations
$ python manage.py migrate
添加了用户模型后,让我们写一个自定义的管理类,允许用文件导入数据。django-import-export 是一个Django应用程序和库,用于导入和导出数据,包括管理集成。
在apps/user/admin.py中,添加以下内容。
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportMixin
from apps.user.models import User
class UserResource(resources.ModelResource):
class Meta:
model = User
fields = ('id', 'username', 'email', 'has_purchased', 'created', 'updated')
@admin.register(User)
class UserAdmin(ImportMixin, admin.ModelAdmin):
resource_class = UserResource
list_display = ('id', 'username', 'email', 'has_purchased', 'created', 'updated')
list_filter = ('has_purchased',)
search_fields = ('username', 'email')
一个资源定义了对象如何被映射到它们的导入和导出表示,并处理导入和导出的数据。在这个文件中,我们声明UserResource类,其中包含模型和数据导入时需要的字段。
UserAdmin类也需要显示的字段,用于过滤数据的字段,以及用于搜索的字段。
👉产品模型
在编写Product 模型之前,我们先创建一个名为product的Django 应用程序。
$ django-admin startapp product
应用程序创建后,修改product目录下的apps.py 文件。
from django.apps import AppConfig
class ProductConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.product'
label = 'apps_product'
然后,让我们在settings.py文件中注册该应用程序。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps',
'apps.product', # <--- NEW
'apps.user',
'import_export',
'rest_framework'
]
我们现在可以编写产品模型了。
from django.db import models
from apps.models import BaseModel
class Product(BaseModel):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity_sold = models.IntegerField(default=0)
def __str__(self):
return self.name
我们还将为产品模型写一个自定义的管理类。在apps/product/admin.py中,添加以下内容。
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportMixin
from apps.product.models import Product
class ProductResource(resources.ModelResource):
class Meta:
model = Product
fields = ('id', 'name', 'price', 'description', 'created')
@admin.register(Product)
class ProductAdmin(ImportMixin, admin.ModelAdmin):
resource_class = ProductResource
list_display = ('id', 'name', 'price', 'description', 'created', 'updated')
list_filter = ('created',)
search_fields = ('name',)
好了,产品管理和用户管理都写好了,我们现在可以动用管理部分来加载数据库中的样本数据(导入/导出功能)。
✨ 加载样本数据
Django提供了一个管理仪表盘,你可以用它来管理我们Django项目的资源(模型、用户、组)。但是在访问仪表板之前,你需要管理员的凭证。
在shell中,输入以下命令来创建一个新的超级用户。
$ django-admin createsuperuser
一旦超级用户被创建,我们就可以访问我们项目的管理部分localhost:admin/ 。在你成功登录后,你会看到一个类似的页面。
让我们先为用户上传数据。点击 "添加",你会被转到以下页面。
你通常会看到第一个用户,就是你刚刚创建的超级用户。很好,现在点击导入。你将不得不导入一个CSV文件。你可以在这里找到这个文件的一个例子。
一旦该文件被导入,点击Confirm Import 。
你的数据库现在已经充满了一些用户的数据🚀。下一步是使用同样的导入功能在产品上加载产品数据,使用样本数据。
✨ 编写序列化器
序列化器允许我们转换Django数据结构,如查询集或模型实例在Python本地对象,可以很容易地转换为JSON/XML格式。让我们先为User模型编写一个序列化器。
👉用户序列化器
在apps/user里面,创建一个叫做serializers.py的文件。这个文件将包含一个名为UserSerializer 的类。
from rest_framework import serializers
from apps.user.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'has_purchased')
ModelSerializer 可以帮助编写基于模型的序列化器,非常容易。它自动匹配字段和它们的类型,甚至添加一些自动验证。
👉产品序列化器
在apps/product/ 目录内,创建一个名为serializers.py 的文件。这个文件将包含一个名为ProductSerializer的模型序列化器。
from rest_framework import serializers
from apps.product.models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'price', 'description', 'created', 'updated')
很好!现在我们有了序列化器,我们可以编写视图集了。
✨ 编写视图集
视图集是一个基于类的视图,能够处理所有的基本HTTP请求。GET, POST, PUT, DELETE,不需要硬编码任何逻辑。我们在这里使用视图集来轻松配置API的路由。
/user/ 视图集应该允许以下结构。
而产品资源将有以下的结构。
👉编写用户视图集
在apps/user/ 目录内,创建一个名为viewsets.py 的文件。该文件将包含一个名为UserViewSet的类。
import calendar
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from apps.user.models import User
from apps.user.serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
http_method_names = ['get']
queryset = User.objects.all()
serializer_class = UserSerializer
@action(detail=False, methods=['get'], url_path='stats/purchased')
def purchase_stats(self, request, *args, **kwargs):
users = User.objects.filter(has_purchased=True)
return Response({
'total_users': User.objects.count(),
'total_purchased': users.count(),
'purchased_percentage': round(users.count() / User.objects.count() * 100, 2)
}, status=status.HTTP_200_OK)
@action(detail=False, methods=['get'], url_path='stats/users_created')
def user_created_per_month(self, request, *args, **kwargs):
users = User.objects.all()
months = []
for user in users:
months.append(user.created.date().month)
months = list(set(months))
months.sort()
data = []
for month in months:
data.append({
'month': calendar.month_name[month],
'count': User.objects.filter(created__month=month).count()
})
return Response(data, status=status.HTTP_200_OK)
在这个viewset ,我们只允许GET 请求。而且我们还为视图集添加了自定义动作,如purchase_stats 和user_created_per_month 。这些动作会计算并返回一些有用的统计信息。
让我们为ProductViewSet做同样的事情。
👉编写产品视图集
在apps/product 目录内,创建一个名为viewsets.py的文件。这个文件将包含ProductViewSet 类。
import calendar
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from apps.product.models import Product
from apps.product.serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
http_method_names = ['get']
queryset = Product.objects.all()
serializer_class = ProductSerializer
@action(detail=False, methods=['get'], url_path='sales')
def sales_over_month(self, request, *args, **kwargs):
products = Product.objects.all()
months = []
for product in products:
months.append(product.created.date().month)
months = list(set(months))
months.sort()
data = []
for month in months:
data.append({
'month': calendar.month_name[month],
'count': Product.objects.filter(created__month=month).count()
})
return Response(data, status=status.HTTP_200_OK)
很好!视图集准备好了,我们可以注册这些视图集来创建端点并开始提出请求。
✨ 编写API端点
由于我们正在使用viewsets ,我们可以使用路由器自动注册API端点。
在apps目录下,创建一个名为routers.py的文件。
from rest_framework import routers
from apps.user.viewsets import UserViewSet
from apps.product.viewsets import ProductViewSet
router = routers.SimpleRouter()
router.register('user', UserViewSet)
router.register('product', ProductViewSet)
urlpatterns = [
*router.urls,
]
然后我们需要在项目的urls.py文件中注册这个文件。然后,这些端点就可以通过浏览器访问了。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path("api/", include(("apps.routers", "api"), namespace="api")),
]
很好!之后,确保服务器正在运行,因为我们将开始进行一些请求。
✨ 集成Chart.JS
Chart.js is a JavaScript library that makes working and building charts easier.在这个项目中,我们将使用这个库来显示线图、棒图和饼图。
图表上显示的数据将来自我们刚刚建立的REST API,我们将使用Axios从服务器上获取数据。
但首先,让我们为Django模板系统和静态文件做一些配置,如JavaScript文件,它将包含数据获取和图表配置的逻辑。
👉配置
首先,确保你在settings.py文件中为TEMPLATES做了如下配置。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'apps/templates')],
'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',
],
},
},
]
模板将在apps/template目录下创建。另外,我们需要对静态文件进行如下配置。
STATIC_URL = 'static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
👉Index.html - 产品主页
在apps/templates ,创建一个名为index.html 的文件。我们只需为bootstrap 、axios 和chartjs 添加基本的导入。
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Chart JS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
<!-- Chart JS -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<title>Stats</title>
</head>
<body>
<h1 class="text-center">Product Stats</h1>
<div class="row">
<!-- LINE Chart -->
<div class="col-6 mr-2">
<h2 class="text-center">
User created over months
</h2>
<canvas id="user-created"></canvas>
</div>
<!-- Bar Chart -->
<div class="col-6 ml-2">
<h2 class="text-center">
Product sales over months
</h2>
<canvas id="product-sales"></canvas>
</div>
<!-- PIE Chart -->
<div class="col-4 mx-auto">
<h2 class="text-center">
Percentage of users who bought a product
</h2>
<canvas id="user-purchased"></canvas>
</div>
</div>
一旦我们有了一个最基本的HTML文件,我们需要编写JS代码,消耗API并将数据注入到图表中。
👉Index.JS - Charts and API
在项目的根目录下,创建一个名为static的目录。在这个目录中,创建另一个叫做js的目录。 这个目录将包含静态的JavaScript文件。最后,在新创建的目录中创建一个index.js文件。
让我们来写写获取和配置图表所需的步骤。
- 添加一个函数来获取数据并返回一个响应
- 从每个端点获取数据
- 用标签初始化数据
- 初始化图表配置
- 最后,在DOM中创建一个图表。
让我们分解每一步,并将必要的代码可视化,以正确呈现我们美丽的图表。
1# - 添加一个函数来获取数据并返回一个响应
async function getData(url) {
const res = await axios.get(url);
return await res.data;
2# - 从每个端点检索数据
let userPurchased = {};
let productSales = [];
let userCreated = [];
// Fetching data for users that have purchased products
userPurchased = getData('/api/user/stats/purchased');
// Fetching data for users created over month
userCreated = getData('/api/user/stats/users_created');
// Fetching data for products sold over month
productSales = getData('/api/product/sales');
3# - 将数据注入图表中
让我们用标签来初始化数据,初始化图表配置,最后在DOM中为userCreate ,创建一个图表。
userCreated.then((response) => {
const dataUserCreated = {
labels: response.map((data) => data.month),
datasets: [{
label: 'Users that have purchased products',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: response.map((data) => data.count),
}]
};
const configUserCreated = {
type: 'line',
data: dataUserCreated,
options: {}
};
// Creating new chart
new Chart(
document.getElementById('user-created'),
configUserCreated
);
})
让我们为userPurchased 和productSales 做同样的事情。
productSales.then((response) => {
const dataProductSales = {
labels: response.map((data) => data.month),
datasets: [{
label: 'Products sold',
data: response.map((data) => data.count),
borderWidth: 1,
backgroundColor: 'rgb(255, 99, 132)',
}]
};
const configProductSales = {
type: 'bar',
data: dataProductSales,
options: {
scales: {
y: {
beginAtZero: true
}
}
},
};
new Chart(
document.getElementById('product-sales'),
configProductSales
);
});
userPurchased.then((response) => {
const dataUserPurchased = {
labels: [
'Total Users',
'Total Purchased',
'Purchased percentage'
],
datasets: [{
label: 'Users created',
data: Object.values(response),
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)'
],
hoverOffset: 4
}]
};
const configUserPurchased = {
type: 'pie',
data: dataUserPurchased,
};
new Chart(
document.getElementById('user-purchased'),
configUserPurchased
);
});
一旦JS部分完全编码完成,最后一步就是更新产品路由并开始使用该项目。
在apps directory ,创建一个views.py 文件,并添加以下内容。
from django.template import loader
from django.shortcuts import render
def index(request):
context = {"segment": "index"}
return render(request, "index.html", context)
并将urls.py 添加到apps目录中,内容如下。
from django.urls import path
from . import views
urlpatterns = [
# The home page
path("", views.index, name="home"),
]
并在项目的urls.py 文件中注册apps/urls.py 。
..
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('apps.urls')),
path("api/", include(("apps.routers", "api"), namespace="api")),
]
..
确保服务器正在运行,然后在浏览器中访问该应用程序。这时,我们应该看到三个图表在主页上漂亮地呈现出来。
✨ 结语
在这篇文章中,我们已经学会了使用Django 和Django REST Framework (DRF)建立一个提供统计数据的API。我们还创建了一个HTML模板来显示由REST API提供的数据,使用Chart.js 和Axios 。
Thanks for reading!如需更多资源,请随时访问。