Django开发中医针灸经络图系统实战
基于 Django Web 开发中医针灸管理经络图系统的实用
以下是基于 Django Web 开发中医针灸管理经络图系统的实用示例,涵盖模型设计、视图逻辑、模板渲染等关键环节,提供典型代码片段:
模型设计(Meridian 和 Acupoint)
# models.py
class Meridian(models.Model):name = models.CharField(max_length=50, verbose_name="经络名称")abbreviation = models.CharField(max_length=10, verbose_name="缩写")description = models.TextField(verbose_name="经络描述")image = models.ImageField(upload_to='meridians/', null=True)def __str__(self):return self.nameclass Acupoint(models.Model):name = models.CharField(max_length=50, verbose_name="穴位名称")code = models.CharField(max_length=10, verbose_name="代号")meridian = models.ForeignKey(Meridian, on_delete=models.CASCADE)location = models.TextField(verbose_name="定位")function = models.TextField(verbose_name="功能")needling_method = models.TextField(verbose_name="针刺方法")class Meta:ordering = ['meridian', 'code']
数据导入示例(JSON 批量导入)
# management/commands/import_meridians.py
from django.core.management.base import BaseCommand
import jsonclass Command(BaseCommand):def handle(self, *args, **options):with open('meridians.json', encoding='utf-8') as f:data = json.load(f)for item in data['meridians']:Meridian.objects.create(name=item['name'],abbreviation=item['abbreviation'],description=item['description'])
视图逻辑(经络列表+搜索)
# views.py
def meridian_list(request):query = request.GET.get('q')meridians = Meridian.objects.all()if query:meridians = meridians.filter(models.Q(name__icontains=query) |models.Q(abbreviation__icontains=query))return render(request, 'tcm/meridian_list.html', {'meridians': meridians})
模板渲染(经络卡片展示)
<!-- templates/tcm/meridian_list.html -->
{% for meridian in meridians %}
<div class="card"><img src="{{ meridian.image.url }}" class="card-img-top"><div class="card-body"><h5>{{ meridian.name }} ({{ meridian.abbreviation }})</h5><p>{{ meridian.description|truncatechars:100 }}</p><a href="{% url 'meridian_detail' meridian.id %}" class="btn btn-primary">查看详情</a></div>
</div>
{% endfor %}
经络详情页(带穴位列表)
# views.py
def meridian_detail(request, pk):meridian = get_object_or_404(Meridian, pk=pk)acupoints = Acupoint.objects.filter(meridian=meridian)return render(request, 'tcm/meridian_detail.html', {'meridian': meridian,'acupoints': acupoints})
交互式经络图(SVG+JavaScript)
<!-- templates/tcm/meridian_map.html -->
<svg id="meridian-map" viewBox="0 0 800 600">{% for meridian in meridians %}<path class="meridian-path" d="{{ meridian.svg_path }}"data-meridian-id="{{ meridian.id }}"fill="none" stroke="#d35400" stroke-width="3"/>{% endfor %}
</svg><script>
document.querySelectorAll('.meridian-path').forEach(path => {path.addEventListener('click', () => {window.location.href = `/meridians/${path.dataset.meridianId}/`;});
});
</script>
REST API 设计(DRF)
# serializers.py
class AcupointSerializer(serializers.ModelSerializer):class Meta:model = Acupointfields = ['id', 'name', 'code', 'location']# views.py
class MeridianViewSet(viewsets.ModelViewSet):queryset = Meridian.objects.all()serializer_class = MeridianSerializer@action(detail=True, methods=['get'])def acupoints(self, request, pk=None):meridian = self.get_object()acupoints = Acupoint.objects.filter(meridian=meridian)serializer = AcupointSerializer(acupoints, many=True)return Response(serializer.data)
穴位搜索(自动完成)
# views.py
class AcupointAutocomplete(autocomplete.Select2QuerySetView):def get_queryset(self):qs = Acupoint.objects.all()if self.q:qs = qs.filter(name__istartswith=self.q)return qs
数据可视化(Chart.js)
// 经络穴位数量统计
const ctx = document.getElementById('meridianChart').getContext('2d');
fetch('/api/meridians/stats/').then(res => res.json()).then(data => {new Chart(ctx, {type: 'bar',data: {labels: data.labels,datasets: [{label: '穴位数量',data: data.counts,backgroundColor: '#e74c3c'}]}});
});
测试用例(模型验证)
# tests.py
class MeridianModelTest(TestCase):@classmethoddef setUpTestData(cls):Meridian.objects.create(name="手太阴肺经",abbreviation="LU",description="起于中焦,下络大肠...")def test_abbreviation_max_length(self):meridian = Meridian.objects.get(id=1)max_length = meridian._meta.get_field('abbreviation').max_lengthself.assertEqual(max_length, 10)
信号处理(图片缩略图生成)
# signals.py
@receiver(models.signals.post_save, sender=Meridian)
def create_meridian_thumbnail(sender, instance, **kwargs):if instance.image:img = Image.open(instance.image.path)img.thumbnail((300, 300))thumb_path = f"{instance.image.path}_thumb"img.save(thumb_path)
管理后台定制
# admin.py
class AcupointInline(admin.TabularInline):model = Acupointextra = 1@admin.register(Meridian)
class MeridianAdmin(admin.ModelAdmin):inlines = [AcupointInline]list_display = ('name', 'abbreviation', 'acupoint_count')def acupoint_count(self, obj):return obj.acupoint_set.count()
表单设计(带富文本编辑)
# forms.py
class MeridianForm(forms.ModelForm):description = forms.CharField(widget=CKEditorWidget())class Meta:model = Meridianfields = ['name', 'abbreviation', 'description', 'image']
权限控制(自定义权限)
# models.py
class Meridian(models.Model):# ... 其他字段 ...class Meta:permissions = [("can_edit_meridian", "Can edit meridian details"),("can_upload_image", "Can upload meridian images"),]
任务队列(生成经络PDF)
# tasks.py
@shared_task
def generate_meridian_pdf(meridian_id):meridian = Meridian.objects.get(pk=meridian_id)html = render_to_string('tcm/meridian_pdf.html', {'meridian': meridian})pdf = HTML(string=html).write_pdf()with open(f'media/meridians/{meridian_id}.pdf', 'wb') as f:f.write(pdf)
国际化和本地化
# models.py
class Acupoint(models.Model):name = models.CharField(_("Acupoint Name"), max_length=50)location = models.TextField(_("Location Description"))# 其他字段...
缓存策略(经络列表缓存)
# views.py
@cache_page(60 * 15)
def meridian_list(request):meridians = Meridian.objects.all().prefetch_related('acupoint_set')return render(request, 'tcm/meridian_list.html', {'meridians': meridians})
日志记录(关键操作)
# views.py
logger = logging.getLogger('tcm.views')def add_acupoint(request):if request.method == 'POST':form = AcupointForm(request.POST)if form.is_valid():acupoint = form.save()logger.info(f'Acupoint created: {acupoint.name}')return redirect('meridian_detail', pk=acupoint.meridian.id)
信号量(数据同步)
# signals.py
@receiver(post_save, sender=Acupoint)
def sync_to_elasticsearch(sender, instance, **kwargs):document = {'name': instance.name,'code': instance.code,'meridian': instance.meridian.name,'location': instance.location}es.index(index='acupoints', id=instance.id, body=document)
微信小程序 API
# api/views.py
class MiniProgramMeridianView(APIView):authentication_classes = [SessionAuthentication]def get(self, request):meridians = Meridian.objects.values('id', 'name', 'abbreviation')return Response({'data': list(meridians)})
数据导出(Excel 报表)
# views.py
def export_meridians(request):response = HttpResponse(content_type='application/ms-excel')response['Content-Disposition'] = 'attachment; filename="meridians.xlsx"'wb = Workbook()ws = wb.activews.append(['ID', 'Name', 'Abbreviation', 'Acupoints Count'])for m in Meridian.objects.all():ws.append([m.id, m.name, m.abbreviation, m.acupoint_set.count()])wb.save(response)return response
实时通知(WebSocket)
# consumers.py
class MeridianConsumer(AsyncWebsocketConsumer):async def connect(self):await self.accept()await self.channel_layer.group_add("meridians", self.channel_name)async def send_update(self, event):await self.send(text_data=json.dumps(event["data"]))
性能优化(select_related)
# views.py
def meridian_detail_optimized(request, pk):meri