布局 API 参考¶
Layout
类管理数据看板内组件的排列。本参考涵盖了布局的创建、配置和高级使用模式。
目录¶
概述¶
什么是布局?¶
布局定义了组件在数据看板上的排列方式:
- 网格系统: 12列响应式网格
- 行与列: 组件按行排列,具有列宽度
- 响应式设计: 适应不同屏幕尺寸
- 组件管理: 组织和定位组件
布局 Concepts¶
- 网格列: 每行总共12列
- 组件宽度: 组件占据的列数 (1-12)
- 行: 组件的水平容器
- 行高度: 行的固定或自动高度
- 嵌套: 组件可以包含子布局 (高级)
导入路径¶
类参考¶
Layout 类¶
class Layout:
"""Layout manager for dashboard"""
def __init__(self, columns=12):
"""Initialize layout with column count"""
def add_row(self, components, height="auto"):
"""Add a row of components"""
def add_component(self, component, width=12):
"""Add a single component as a row"""
构造函数¶
__init__(columns=12)¶
参数:
columns(int): 网格中的列数 (默认: 12)
返回: Layout 实例
描述:
使用指定的列数创建新的布局管理器。
使用:
# Default 12-column layout (recommended)
layout = Layout()
# Custom column count (advanced use)
layout = Layout(columns=16)
方法¶
add_row(components, height="auto")¶
参数:
- components (list): (component, width) 元组列表
- height (str): 行高度,CSS单位或"auto"
返回: self (用于方法链式调用)
描述:
添加包含多个组件的行。
组件 Format:
高度值: - "auto": 高度由内容决定 - "400px": 固定高度(像素) -
"50vh": 视口高度的百分比 - "min-content": 所需最小高度
使用:
layout.add_row([
(card1, 6), # 6 columns (50% width)
(card2, 6) # 6 columns (50% width)
], height="auto")
add_component(component, width=12)¶
参数:
- component (Component): 组件实例
- width (int): 列宽度 (1-12, 默认: 12)
返回: self (用于方法链式调用)
描述:
将单个组件添加为完整行。
使用:
# Full-width component
layout.add_component(full_width_chart)
# Half-width component (creates a row with one component)
layout.add_component(half_width_card, width=6)
属性¶
| 属性 | 类型 | 描述 |
|---|---|---|
columns |
int |
网格中的列数 |
rows |
list |
行字典列表 |
行 Structure¶
Layout.rows 中的每一行具有以下结构:
row = {
"components": [
(component_instance, column_width),
# ... more components
],
"height": "400px" # or "auto", "50vh", etc.
}
基础 使用¶
创建布局¶
from django_admin_dashboards.base import Layout, CardComponent, ChartComponent
# 创建布局
layout = Layout(columns=12)
# 添加组件
card1 = CardComponent(title="Card 1", value=100)
card2 = CardComponent(title="Card 2", value=200)
chart = ChartComponent(title="Chart", chart_type="line", data={})
# 添加包含两张卡片的行 (每张6列)
layout.add_row([
(card1, 6),
(card2, 6)
])
# 添加全宽图表
layout.add_row([
(chart, 12)
])
# 替代方案:添加单个组件
layout.add_component(card1, width=12)
数据看板中的布局¶
from django_admin_dashboards.base import Dashboard, Layout, CardComponent
class MyDashboard(Dashboard):
def get_layout(self):
layout = Layout(columns=12)
# 创建组件
users_card = CardComponent(
title="Total Users",
value=User.objects.count()
)
sales_card = CardComponent(
title="Today's Sales",
value=1500,
change="+12%"
)
# 在布局中排列
layout.add_row([
(users_card, 6),
(sales_card, 6)
])
return layout
方法链式调用¶
布局方法支持链式调用:
layout = Layout() \
.add_row([(card1, 4), (card2, 4), (card3, 4)]) \
.add_row([(chart1, 8), (chart2, 4)]) \
.add_component(full_width_table)
验证列宽度¶
布局系统验证列宽度:
# 有效:总和为12
layout.add_row([(c1, 6), (c2, 6)]) # 6 + 6 = 12 ✓
layout.add_row([(c1, 4), (c2, 4), (c3, 4)]) # 4 + 4 + 4 = 12 ✓
# 无效:总和不为12
# layout.add_row([(c1, 6), (c2, 8)]) # 6 + 8 = 14 ✗ (would raise error)
# 单个组件可以是1-12之间的任意宽度
layout.add_component(c1, width=8) # Valid ✓
布局模式¶
等宽列¶
# 两等宽列
layout.add_row([(component1, 6), (component2, 6)])
# 三等宽列
layout.add_row([(c1, 4), (c2, 4), (c3, 4)])
# 四等宽列
layout.add_row([(c1, 3), (c2, 3), (c3, 3), (c4, 3)])
# 六等宽列
layout.add_row([(c1, 2), (c2, 2), (c3, 2), (c4, 2), (c5, 2), (c6, 2)])
非对称布局¶
# 主次布局 (8-4)
layout.add_row([(main_content, 8), (sidebar, 4)])
# 三分之二对三分之一 (8-4)
layout.add_row([(primary, 8), (secondary, 4)])
# 四分之三对四分之一 (9-3)
layout.add_row([(main, 9), (aside, 3)])
# 黄金比例近似 (7-5)
layout.add_row([(golden_main, 7), (golden_side, 5)])
混合宽度模式¶
# 数据看板标题模式
layout.add_row([(title_card, 12)]) # 全宽标题
layout.add_row([(kpi1, 3), (kpi2, 3), (kpi3, 3), (kpi4, 3)]) # 4个卡片
layout.add_row([(main_chart, 8), (sidebar_stats, 4)]) # 带统计的图表
layout.add_row([(table, 12)]) # 全宽表格
垂直堆叠¶
# 垂直堆叠组件(每个全宽)
layout.add_component(component1) # width=12 by default
layout.add_component(component2)
layout.add_component(component3)
水平流¶
高级技术¶
动态布局¶
基于数据或条件创建布局:
def get_layout(self):
layout = Layout(columns=12)
# 基于用户角色添加组件
if self.request.user.is_superuser:
components = self.get_admin_components()
else:
components = self.get_user_components()
# 动态排列组件
row = []
total_width = 0
for component in components:
width = component.preferred_width or 6
if total_width + width > 12:
# 开始新行
layout.add_row(row)
row = [(component, width)]
total_width = width
else:
# 添加到当前行
row.append((component, width))
total_width += width
# 添加最后一行
if row:
layout.add_row(row)
return layout
嵌套布局(概念性)¶
虽然不直接支持,但您可以模拟嵌套布局:
def create_nested_layout(self):
"""创建具有概念性嵌套的布局"""
layout = Layout(columns=12)
# 顶层:标题
layout.add_row([(header, 12)])
# 中间:主要内容区域
main_layout = self.create_main_content_layout()
layout.add_row([(main_layout_component, 12)])
# 底部:页脚
layout.add_row([(footer, 12)])
return layout
def create_main_content_layout(self):
"""为主要内容区域创建布局"""
sub_layout = Layout(columns=12)
# 侧边栏(概念性嵌套)
sidebar_components = self.get_sidebar_components()
for component in sidebar_components:
sub_layout.add_component(component, width=3)
# 主要内容(概念性嵌套)
main_components = self.get_main_components()
for component in main_components:
sub_layout.add_component(component, width=9)
return sub_layout
条件行¶
基于条件显示/隐藏行:
def get_layout(self):
layout = Layout(columns=12)
# 始终显示标题
layout.add_row([(header_card, 12)])
# 条件行:仅适用于管理员
if self.request.user.is_staff:
layout.add_row([(admin_stats, 12)])
# 基于数据的条件
if self.has_alerts():
layout.add_row([(alerts_panel, 12)])
# 基于视图模式显示不同的布局
view_mode = self.request.GET.get('view', 'standard')
if view_mode == 'minimal':
return self.get_minimal_layout()
elif view_mode == 'detailed':
return self.get_detailed_layout()
else:
# 标准布局
layout.add_row([(main_content, 12)])
return layout
布局模板¶
创建可重用的布局模式:
class LayoutTemplates:
"""可重用的布局模式"""
@staticmethod
def card_dashboard(cards):
"""卡片数据看板布局:一行4张卡片"""
layout = Layout(columns=12)
if len(cards) == 4:
layout.add_row([
(cards[0], 3),
(cards[1], 3),
(cards[2], 3),
(cards[3], 3)
])
elif len(cards) == 6:
# 第一行:3张卡片
layout.add_row([
(cards[0], 4),
(cards[1], 4),
(cards[2], 4)
])
# 第二行:3张卡片
layout.add_row([
(cards[3], 4),
(cards[4], 4),
(cards[5], 4)
])
return layout
@staticmethod
def main_with_sidebar(main_component, sidebar_components):
"""带有主要内容和侧边栏的布局"""
layout = Layout(columns=12)
# 添加侧边栏组件
sidebar_layout = Layout(columns=12)
for component in sidebar_components:
sidebar_layout.add_component(component, width=12)
# Main layout (8 columns main, 4 columns sidebar)
layout.add_row([
(main_component, 8),
(sidebar_layout, 4) # Note: passing layout as component
])
return layout
# Usage
layout = LayoutTemplates.card_dashboard(cards)
布局 Inheritance¶
Extend existing layouts:
class BaseLayout(Layout):
"""Base layout with common configuration"""
def __init__(self, columns=12):
super().__init__(columns)
self.common_rows = []
def add_common_header(self):
"""Add common header to layout"""
header = CardComponent(title="Dashboard", value="Overview")
self.add_row([(header, 12)])
return self
def add_common_footer(self):
"""Add common footer to layout"""
footer = CardComponent(title="Last Updated", value=timezone.now())
self.add_row([(footer, 12)])
return self
class CustomLayout(BaseLayout):
"""Custom layout extending base"""
def create_dashboard_layout(self, components):
"""Create complete dashboard layout"""
self.add_common_header()
# Add components in rows of 3
for i in range(0, len(components), 3):
row_components = components[i:i+3]
widths = [4, 4, 4][:len(row_components)]
self.add_row(list(zip(row_components, widths)))
self.add_common_footer()
return self
响应式设计¶
CSS 网格基础¶
布局系统使用CSS网格实现响应式设计:
/* 基础网格系统 */
.dashboard-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 20px;
width: 100%;
}
/* 列跨度 */
.col-span-1 { grid-column: span 1; }
.col-span-2 { grid-column: span 2; }
.col-span-3 { grid-column: span 3; }
.col-span-4 { grid-column: span 4; }
.col-span-5 { grid-column: span 5; }
.col-span-6 { grid-column: span 6; }
.col-span-7 { grid-column: span 7; }
.col-span-8 { grid-column: span 8; }
.col-span-9 { grid-column: span 9; }
.col-span-10 { grid-column: span 10; }
.col-span-11 { grid-column: span 11; }
.col-span-12 { grid-column: span 12; }
响应式断点¶
内置响应式行为:
屏幕尺寸 列行为
桌面 (> 1200px) 完整12列布局 平板 (768px - 1199px) 组件可能堆叠 移动设备 (\< 768px) 单列布局
自定义响应式规则¶
使用自定义CSS覆盖响应式行为:
/* dashboard.css - 响应式覆盖 */
/* 平板:每行2列 */
@media (max-width: 1199px) and (min-width: 768px)
.dashboard-col.col-span-3 {
grid-column: span 6 !important; /* 3 → 6 columns */
}
}
/* Mobile: single column */
@media (max-width: 767px)
}
/* Large desktop: more spacing */
@media (min-width: 1400px)
}
组件-aware Responsiveness¶
Make components 响应式 基于 screen size:
class ResponsiveDashboard(Dashboard):
def get_layout(self):
layout = Layout(columns=12)
# Detect screen size from request (simplified)
user_agent = self.request.META.get('HTTP_USER_AGENT', '')
is_mobile = 'Mobile' in user_agent
if is_mobile:
# Mobile layout: single column
for component in self.get_components():
layout.add_component(component, width=12)
else:
# Desktop layout: multiple columns
layout.add_row([
(self.get_card1(), 3),
(self.get_card2(), 3),
(self.get_card3(), 3),
(self.get_card4(), 3)
])
return layout
最佳实践¶
1. 规划您的布局¶
在编码前草图绘制您的布局:
# 布局草图:
# ┌─────────────┬─────────────┐
# │ Card 1 │ Card 2 │ (6 columns each)
# ├─────────────┴─────────────┤
# │ Full Chart │ (12 columns)
# ├─────────────┬─────────────┤
# │ Table 1 │ Table 2 │ (6 columns each)
# └─────────────┴─────────────┘
def get_layout(self):
layout = Layout(columns=12)
# 第1行:两张卡片
layout.add_row([
(self.create_card1(), 6),
(self.create_card2(), 6)
])
# 第2行:全宽图表
layout.add_row([
(self.create_main_chart(), 12)
])
# 第3行:两个表格
layout.add_row([
(self.create_table1(), 6),
(self.create_table2(), 6)
])
return layout
2. 平衡列宽度¶
保持列宽度平衡且合理:
# 良好:平衡且总和为12
layout.add_row([(c1, 4), (c2, 4), (c3, 4)]) # 4+4+4=12 ✓
layout.add_row([(c1, 6), (c2, 6)]) # 6+6=12 ✓
# 避免:不平衡且难以阅读
layout.add_row([(c1, 2), (c2, 3), (c3, 7)]) # 2+3+7=12 but unbalanced
3. 使用一致的高度¶
保持行高度一致以实现视觉和谐:
# 一致的高度
layout.add_row([(card1, 6), (card2, 6)], height="200px")
layout.add_row([(chart1, 8), (chart2, 4)], height="400px")
layout.add_row([(table, 12)], height="auto") # Let content determine height
# 避免在同一数据看板中混合固定高度和自动高度
4. 分组相关组件¶
将相关组件保持在一起:
def get_layout(self):
layout = Layout(columns=12)
# 用户统计分组
layout.add_row([(user_header, 12)])
layout.add_row([
(total_users, 3),
(active_users, 3),
(new_users, 3),
(churned_users, 3)
])
# Sales group
layout.add_row([(sales_header, 12)])
layout.add_row([
(revenue_chart, 8),
(sales_card, 4)
])
return layout
5. 优化性能¶
最小化布局计算:
class OptimizedDashboard(Dashboard):
def __init__(self, request=None):
super().__init__(request)
self._layout_cache = None
def get_layout(self):
# 缓存布局以避免重复计算
if self._layout_cache is None:
self._layout_cache = self._create_layout()
return self._layout_cache
def _create_layout(self):
"""实际创建布局(仅调用一次)"""
layout = Layout(columns=12)
# 构建布局一次
# ... layout building code ...
return layout
6. 测试布局响应性¶
在不同的屏幕尺寸下测试您的布局:
from django.test import TestCase
from django.test.client import RequestFactory
class LayoutTests(TestCase):
def test_layout_creation(self):
layout = Layout(columns=12)
self.assertEqual(layout.columns, 12)
def test_row_creation(self):
layout = Layout()
card = CardComponent(title="Test", value=100)
layout.add_row([(card, 12)])
self.assertEqual(len(layout.rows), 1)
self.assertEqual(layout.rows[0]["components"][0][1], 12)
def test_column_sum_validation(self):
layout = Layout()
card1 = CardComponent(title="Test1", value=100)
card2 = CardComponent(title="Test2", value=200)
# 这应该能工作
layout.add_row([(card1, 6), (card2, 6)])
# 这可能会失败(取决于实现)
# layout.add_row([(card1, 7), (card2, 6)]) # 7+6=13 > 12
7. 记录布局决策¶
记录您选择特定布局的原因:
class DocumentedDashboard(Dashboard):
"""
数据看板布局文档:
1. 标题行:全宽标题
2. 卡片行:4张卡片(每张3列)- 显示关键指标
3. 图表行:主图表(8列)带侧边栏(4列)
4. 表格行:全宽用于详细数据
响应式行为:
- 桌面:12列网格
- 平板:每行2列
- 移动设备:每行1列
"""
def get_layout(self):
# 实现遵循上述文档
pass
常见问题与解决方案¶
组件溢出¶
问题: 组件不适合12列网格。
解决方案: 在添加前验证列总和:
def add_validated_row(self, layout, components_with_widths):
"""添加带验证的行"""
total_width = sum(width for _, width in components_with_widths)
if total_width != 12:
# 按比例调整宽度
adjusted = []
for component, width in components_with_widths:
adjusted_width = int((width / total_width) * 12)
adjusted.append((component, adjusted_width))
components_with_widths = adjusted
layout.add_row(components_with_widths)
return layout
组件高度不均匀¶
问题: 同一行中的组件高度不同。
解决方案: 1. 为行设置固定高度 2. 使用CSS平衡高度 3. 将相似高度的组件分组在一起
# 设置固定高度
layout.add_row([(tall_component, 6), (short_component, 6)], height="300px")
# 或使用CSS
.dashboard-row {
display: grid;
grid-template-columns: repeat(12, 1fr);
align-items: stretch; /* 使子元素等高 */
}
.dashboard-col {
height: 100%; /* Take full height of row */
}
响应式布局断裂¶
问题: 布局不能很好地适应移动设备。
解决方案: 使用CSS媒体查询并彻底测试:
多组件性能¶
问题: 包含许多组件的数据看板加载缓慢。
解决方案: 1. 分页或懒加载组件 2. 缓存布局和数据 3. 使用较小的初始布局,按需扩展
class LazyDashboard(Dashboard):
def get_initial_layout(self):
"""返回最小初始布局"""
layout = Layout(columns=12)
layout.add_row([(self.get_essential_cards(), 12)])
return layout
def get_full_layout(self):
"""返回完整布局(按需加载)"""
layout = Layout(columns=12)
# ... all components ...
return layout
布局 示例 参考¶
分析 数据看板¶
def create_analytics_layout(self):
"""数据看板布局"""
layout = Layout(columns=12)
# 1. Header with key metrics
layout.add_row([(self.create_dashboard_title(), 12)])
# 2. Top cards (4 cards)
cards = self.get_cards()
layout.add_row([
(cards[0], 3),
(cards[1], 3),
(cards[2], 3),
(cards[3], 3)
])
# 3. Main charts (2 charts side by side)
layout.add_row([
(self.create_main_chart(), 8),
(self.create_secondary_chart(), 4)
])
# 4. Detailed data tables
layout.add_row([(self.create_data_table(), 12)])
# 5. Footer with insights
layout.add_row([(self.create_insights_panel(), 12)])
return layout
Monitoring 数据看板¶
def create_monitoring_layout(self):
"""系统监控布局"""
layout = Layout(columns=12)
# 全宽状态横幅
layout.add_row([(self.create_status_banner(), 12)])
# 网格中的系统指标
metrics = self.get_system_metrics()
for i in range(0, len(metrics), 3):
row_metrics = metrics[i:i+3]
layout.add_row([
(row_metrics[0], 4),
(row_metrics[1], 4),
(row_metrics[2], 4)
])
# 警报面板和图表
layout.add_row([
(self.create_alerts_panel(), 4),
(self.create_performance_chart(), 8)
])
return layout
Executive 数据看板¶
def create_executive_layout(self):
"""为高管简化的布局"""
layout = Layout(columns=12)
# 简洁、极简的设计
layout.add_row([(self.create_executive_summary(), 12)], height="auto")
# 仅关键指标
key_metrics = self.get_key_metrics()
layout.add_row([
(key_metrics[0], 4),
(key_metrics[1], 4),
(key_metrics[2], 4)
], height="150px")
# 单个重要图表
layout.add_row([(self.create_primary_chart(), 12)], height="500px")
return layout
相关文档¶
- 数据看板 API - 数据看板类与布局集成
- 组件 API - 用于布局的组件类
- 用户指南: 布局系统 - 实用布局指南
- 示例 - 真实世界布局示例