每天40分玩转Django:Django实战 - 在线打印服务体系

打印 上一主题 下一主题

主题 911|帖子 911|积分 2733

Django实战 - 在线打印服务体系

一、体系功能概览表

模块重要功能技术要点文件上传PDF/Word文件上传、文件验证文件处理惩罚、MIME类型验证异步处理惩罚文件转换、打印队列Celery、Redis通知邮件打印状态通知、订单确认SMTP、邮件模板 二、体系架构设计

2.1 模型设计

  1. # models.py
  2. from django.db import models
  3. from django.contrib.auth.models import User
  4. from django.core.validators import FileExtensionValidator
  5. class PrintJob(models.Model):
  6.     STATUS_CHOICES = (
  7.         ('pending', '等待处理'),
  8.         ('processing', '处理中'),
  9.         ('completed', '已完成'),
  10.         ('failed', '失败'),
  11.     )
  12.    
  13.     user = models.ForeignKey(User, on_delete=models.CASCADE)
  14.     document = models.FileField(
  15.         upload_to='documents/%Y/%m/%d/',
  16.         validators=[FileExtensionValidator(allowed_extensions=['pdf', 'doc', 'docx'])]
  17.     )
  18.     copies = models.IntegerField(default=1)
  19.     double_sided = models.BooleanField(default=True)
  20.     color = models.BooleanField(default=False)
  21.     status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
  22.     created_at = models.DateTimeField(auto_now_add=True)
  23.     updated_at = models.DateTimeField(auto_now=True)
  24.     notes = models.TextField(blank=True)
  25.     page_count = models.IntegerField(null=True, blank=True)
  26.     estimated_cost = models.DecimalField(max_digits=10, decimal_places=2, null=True)
  27.    
  28.     def __str__(self):
  29.         return f"Print Job #{self.id} - {self.user.username}"
  30. class PrintNotification(models.Model):
  31.     print_job = models.ForeignKey(PrintJob, on_delete=models.CASCADE)
  32.     sent_at = models.DateTimeField(auto_now_add=True)
  33.     message = models.TextField()
  34.     is_read = models.BooleanField(default=False)
复制代码
2.2 文件上传处理惩罚

  1. # forms.py
  2. from django import forms
  3. from .models import PrintJob
  4. class PrintJobForm(forms.ModelForm):
  5.     class Meta:
  6.         model = PrintJob
  7.         fields = ['document', 'copies', 'double_sided', 'color', 'notes']
  8.         
  9.     def clean_document(self):
  10.         document = self.cleaned_data.get('document')
  11.         if document:
  12.             if document.size > 20 * 1024 * 1024:  # 20MB限制
  13.                 raise forms.ValidationError('文件大小不能超过20MB')
  14.         return document
  15. # views.py
  16. from django.shortcuts import render, redirect
  17. from django.contrib.auth.decorators import login_required
  18. from django.contrib import messages
  19. from .forms import PrintJobForm
  20. from .tasks import process_print_job
  21. @login_required
  22. def submit_print_job(request):
  23.     if request.method == 'POST':
  24.         form = PrintJobForm(request.POST, request.FILES)
  25.         if form.is_valid():
  26.             print_job = form.save(commit=False)
  27.             print_job.user = request.user
  28.             print_job.save()
  29.             
  30.             # 启动异步任务
  31.             process_print_job.delay(print_job.id)
  32.             
  33.             messages.success(request, '打印任务已提交,请等待处理')
  34.             return redirect('print_job_status', job_id=print_job.id)
  35.     else:
  36.         form = PrintJobForm()
  37.    
  38.     return render(request, 'print/submit.html', {'form': form})
复制代码
2.3 Celery异步使命设置

  1. # celery.py
  2. from __future__ import absolute_import, unicode_literals
  3. import os
  4. from celery import Celery
  5. from django.conf import settings
  6. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
  7. app = Celery('print_service')
  8. app.config_from_object('django.conf:settings', namespace='CELERY')
  9. app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
  10. # tasks.py
  11. from celery import shared_task
  12. from django.core.mail import send_mail
  13. from django.template.loader import render_to_string
  14. from .models import PrintJob
  15. @shared_task
  16. def process_print_job(job_id):
  17.     try:
  18.         print_job = PrintJob.objects.get(id=job_id)
  19.         print_job.status = 'processing'
  20.         print_job.save()
  21.         
  22.         # 处理文件并计算页数
  23.         page_count = calculate_page_count(print_job.document)
  24.         print_job.page_count = page_count
  25.         
  26.         # 计算估计成本
  27.         cost = calculate_cost(page_count, print_job.color, print_job.double_sided)
  28.         print_job.estimated_cost = cost
  29.         
  30.         # 模拟打印过程
  31.         import time
  32.         time.sleep(5)  # 模拟打印时间
  33.         
  34.         print_job.status = 'completed'
  35.         print_job.save()
  36.         
  37.         # 发送完成通知
  38.         send_completion_email.delay(job_id)
  39.         
  40.     except Exception as e:
  41.         print_job.status = 'failed'
  42.         print_job.notes = str(e)
  43.         print_job.save()
  44.         
  45. @shared_task
  46. def send_completion_email(job_id):
  47.     print_job = PrintJob.objects.get(id=job_id)
  48.     context = {
  49.         'job': print_job,
  50.         'user': print_job.user,
  51.     }
  52.    
  53.     html_message = render_to_string('print/email/completion.html', context)
  54.    
  55.     send_mail(
  56.         subject='您的打印任务已完成',
  57.         message=f'打印任务 #{print_job.id} 已完成,请及时取件。',
  58.         html_message=html_message,
  59.         from_email='printservice@example.com',
  60.         recipient_list=[print_job.user.email],
  61.         fail_silently=False,
  62.     )
复制代码
2.4 邮件模板设计

  1. <!-- templates/print/email/completion.html -->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5.     <meta charset="utf-8">
  6.     <style>
  7.         .container { padding: 20px; }
  8.         .header { color: #333; }
  9.         .details { margin: 20px 0; }
  10.         .footer { color: #666; font-size: 12px; }
  11.     </style>
  12. </head>
  13. <body>
  14.     <div class="container">
  15.         <h2 class="header">打印任务完成通知</h2>
  16.         <div class="details">
  17.             <p>尊敬的 {{ user.username }}:</p>
  18.             <p>您的打印任务已经完成,详情如下:</p>
  19.             <ul>
  20.                 <li>任务编号:#{{ job.id }}</li>
  21.                 <li>页数:{{ job.page_count }}</li>
  22.                 <li>费用:¥{{ job.estimated_cost }}</li>
  23.                 <li>完成时间:{{ job.updated_at|date:"Y-m-d H:i" }}</li>
  24.             </ul>
  25.             <p>请尽快到打印点取件,谢谢!</p>
  26.         </div>
  27.         <div class="footer">
  28.             <p>此邮件为系统自动发送,请勿回复。</p>
  29.         </div>
  30.     </div>
  31. </body>
  32. </html>
复制代码
三、流程图设计


四、实用工具函数

  1. # utils.py
  2. import os
  3. import PyPDF2
  4. from docx import Document
  5. def calculate_page_count(document):
  6.     """计算文档页数"""
  7.     file_extension = os.path.splitext(document.name)[1].lower()
  8.    
  9.     if file_extension == '.pdf':
  10.         with document.open('rb') as pdf_file:
  11.             pdf_reader = PyPDF2.PdfReader(pdf_file)
  12.             return len(pdf_reader.pages)
  13.             
  14.     elif file_extension in ['.doc', '.docx']:
  15.         doc = Document(document)
  16.         return len(doc.paragraphs) // 40  # 估算页数
  17.    
  18.     return 0
  19. def calculate_cost(page_count, is_color, is_double_sided):
  20.     """计算打印费用"""
  21.     base_price = 0.5  # 单面黑白价格
  22.    
  23.     if is_color:
  24.         base_price *= 3  # 彩印价格是黑白的3倍
  25.    
  26.     if is_double_sided:
  27.         # 双面打印优惠10%
  28.         total_pages = (page_count + 1) // 2
  29.         return round(total_pages * base_price * 0.9, 2)
  30.    
  31.     return round(page_count * base_price, 2)
复制代码
五、单元测试

  1. # tests.py
  2. from django.test import TestCase, Client
  3. from django.contrib.auth.models import User
  4. from django.core import mail
  5. from django.core.files.uploadedfile import SimpleUploadedFile
  6. from .models import PrintJob
  7. from .tasks import process_print_job
  8. class PrintServiceTests(TestCase):
  9.     def setUp(self):
  10.         self.client = Client()
  11.         self.user = User.objects.create_user(
  12.             username='testuser',
  13.             email='test@example.com',
  14.             password='testpass123'
  15.         )
  16.         
  17.         # 创建测试PDF文件
  18.         self.test_file = SimpleUploadedFile(
  19.             "test.pdf",
  20.             b"file_content",
  21.             content_type="application/pdf"
  22.         )
  23.         
  24.     def test_print_job_creation(self):
  25.         """测试打印任务创建"""
  26.         self.client.login(username='testuser', password='testpass123')
  27.         
  28.         response = self.client.post('/print/submit/', {
  29.             'document': self.test_file,
  30.             'copies': 1,
  31.             'double_sided': True,
  32.             'color': False,
  33.         })
  34.         
  35.         self.assertEqual(response.status_code, 302)
  36.         self.assertEqual(PrintJob.objects.count(), 1)
  37.         
  38.     def test_email_notification(self):
  39.         """测试邮件通知"""
  40.         print_job = PrintJob.objects.create(
  41.             user=self.user,
  42.             document=self.test_file,
  43.             status='processing'
  44.         )
  45.         
  46.         process_print_job(print_job.id)
  47.         
  48.         self.assertEqual(len(mail.outbox), 1)
  49.         self.assertEqual(mail.outbox[0].to[0], self.user.email)
复制代码
六、部署设置

  1. # settings.py
  2. # Celery配置
  3. CELERY_BROKER_URL = 'redis://localhost:6379/0'
  4. CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
  5. CELERY_ACCEPT_CONTENT = ['json']
  6. CELERY_TASK_SERIALIZER = 'json'
  7. CELERY_RESULT_SERIALIZER = 'json'
  8. CELERY_TIMEZONE = 'Asia/Shanghai'
  9. # 邮件配置
  10. EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
  11. EMAIL_HOST = 'smtp.example.com'
  12. EMAIL_PORT = 587
  13. EMAIL_USE_TLS = True
  14. EMAIL_HOST_USER = 'your-email@example.com'
  15. EMAIL_HOST_PASSWORD = 'your-email-password'
  16. # 文件上传配置
  17. MEDIA_URL = '/media/'
  18. MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  19. FILE_UPLOAD_MAX_MEMORY_SIZE = 20 * 1024 * 1024  # 20MB
  20. FILE_UPLOAD_PERMISSIONS = 0o644
复制代码
七、安全考虑


  • 文件上传安全:

    • 限制文件大小和类型
    • 使用安全的文件存储位置
    • 实行病毒扫描

  • 用户认证:

    • 要求用户登录
    • 实行访问控制
    • 防止未授权访问

  • 异步使命安全:

    • 使命队列加密
    • 错误处理惩罚和重试机制
    • 监控和日志记录

八、性能优化发起


  • 文件处理惩罚优化:

    • 使用分块上传
    • 实现断点续传
    • 文件压缩处理惩罚

  • 使命队列优化:

    • 公道设置并发数
    • 实现使命优先级
    • 添加使命超时机制

  • 邮件发送优化:

    • 使用邮件队列
    • 批量处理惩罚通知
    • 模板预编译

九、后续扩展发起


  • 功能扩展:

    • 添加打印预览
    • 支持更多文件格式
    • 实现打印参数设置

  • 用户体验提升:

    • 添加进度条显示
    • 实时状态更新
    • 打印汗青记录

  • 管理功能:

    • 打印机管理
    • 耗材管理
    • 统计报表

本节课程介绍了如何使用Django框架构建一个在线打印服务体系,包括文件上传、异步处理惩罚和邮件通知等核心功能。发起学习者在理解根本代码的同时,注意体系的安全性和性能优化,并根据实际需求举行功能扩展。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表