用 Django 5 快速生成一个简单 进销存 系统 添加 个打印 按钮

发布于:2024-10-12 ⋅ 阅读:(123) ⋅ 点赞:(0)

一、前置条件:

1.安装好python 【关联网址

2. 安装好vscode 【关联网址】 

插件

3. 登陆海螺AI【关联网址

4. 安装好 pip install django 【关联网址】 

pip install django -i https://mirrors.aliyun.com/pypi/simple/

二、开始生成

1. 打开vscode 打开终端输入以下命令

django-admin startproject myapp

cd myapp

py manage.py startapp app

# 下面生成 目录 用于修改后台,二次开发用
md templates/admin

2、数据库 对海螺AI  问 : 设计一个进销存数据库

设计一个进销存(Inventory Management System)数据库需要考虑几个关键实体和它们之间的关系。以下是一个基本的进销存数据库设计示例,包括了一些核心表和它们的字段。

### 核心实体和字段

#### 1. 商品(Products)
- 商品ID(ProductID): 主键,唯一标识每个商品。
- 商品名称(ProductName): 商品的名称。
- 商品描述(Description): 商品的详细描述。
- 单位成本(CostPrice): 商品的采购成本。
- 销售价格(SellingPrice): 商品的销售价格。
- 库存数量(StockQuantity): 当前库存中的商品数量。
- 分类ID(CategoryID): 外键,关联到商品分类表。

#### 2. 商品分类(Categories)
- 分类ID(CategoryID): 主键,唯一标识每个分类。
- 分类名称(CategoryName): 分类的名称。

#### 3. 供应商(Suppliers)
- 供应商ID(SupplierID): 主键,唯一标识每个供应商。
- 供应商名称(SupplierName): 供应商的名称。
- 联系信息(ContactInfo): 供应商的联系信息。

#### 4. 客户(Customers)
- 客户ID(CustomerID): 主键,唯一标识每个客户。
- 客户名称(CustomerName): 客户的名称。
- 联系信息(ContactInfo): 客户的联系信息。

#### 5. 订单(Orders)
- 订单ID(OrderID): 主键,唯一标识每个订单。
- 客户ID(CustomerID): 外键,关联到客户表。
- 订单日期(OrderDate): 订单的日期。
- 总金额(TotalAmount): 订单的总金额。

#### 6. 订单详情(OrderDetails)
- 订单详情ID(OrderDetailID): 主键,唯一标识订单详情。
- 订单ID(OrderID): 外键,关联到订单表。
- 商品ID(ProductID): 外键,关联到商品表。
- 购买数量(QuantityPurchased): 购买的商品数量。
- 单价(UnitPrice): 购买时的商品单价。

#### 7. 采购记录(Purchases)
- 采购记录ID(PurchaseID): 主键,唯一标识每次采购。
- 供应商ID(SupplierID): 外键,关联到供应商表。
- 采购日期(PurchaseDate): 采购的日期。
- 总金额(TotalCost): 采购的总金额。

#### 8. 采购详情(PurchaseDetails)
- 采购详情ID(PurchaseDetailID): 主键,唯一标识采购详情。
- 采购记录ID(PurchaseID): 外键,关联到采购记录表。
- 商品ID(ProductID): 外键,关联到商品表。
- 购入数量(QuantityReceived): 购入的商品数量。
- 单价(UnitPrice): 购入时的商品单价。

### 关系
- 商品与分类是多对一的关系,即一个商品属于一个分类,一个分类可以包含多个商品。
- 订单与客户是多对一的关系,即一个客户可以有多个订单,但每个订单只属于一个客户。
- 订单详情与订单是多对一的关系,即一个订单可以包含多个商品,但每个订单详情只属于一个订单。
- 订单详情与商品是多对一的关系,即一个商品可以在多个订单中出现,但每个订单详情只涉及一个商品。
- 采购记录与供应商是多对一的关系,即一个供应商可以有多次采购记录,但每次采购记录只对应一个供应商。
- 采购详情与采购记录是多对一的关系,即一次采购记录可以包含多个商品,但每个采购详情只属于一次采购记录。
- 采购详情与商品是多对一的关系,即一个商品可以被多次采购,但每个采购详情只涉及一个商品。

### 数据库设计注意事项
- 确保主键的唯一性。
- 使用外键来维护表之间的关系。
- 考虑索引的使用,以提高查询效率。
- 根据实际业务需求,可能还需要添加额外的字段或表,例如员工信息、库存变动记录等。

这个设计是一个基础版本,实际应用中可能需要根据具体业务需求进行调整和扩展。

第二问:根据上面的数据库生成django 5 的models

第三问:舔加中文标识

第四问:生成admin.py

三、 再改生成app/models.py

from django.db import models

# 商品分类模型
class Category(models.Model):
    category_name = models.CharField("分类名称", max_length=100, unique=True)
    # 其他字段...
    class Meta:
        verbose_name = "分类"
        verbose_name_plural = "分类"

    def __str__(self):
        return self.category_name

# 商品模型
class Product(models.Model):
    product_name = models.CharField("商品名称", max_length=255)
    description = models.TextField("商品描述")
    cost_price = models.DecimalField("成本价格", max_digits=10, decimal_places=2)
    selling_price = models.DecimalField("销售价格", max_digits=10, decimal_places=2)
    stock_quantity = models.IntegerField("库存数量")
    category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name="分类")

    class Meta:
        verbose_name = "商品"
        verbose_name_plural = "商品"
    def __str__(self):
        return self.product_name

# 供应商模型
class Supplier(models.Model):
    supplier_name = models.CharField("供应商名称", max_length=255)
    contact_info = models.TextField("联系信息")
    address = models.CharField("地址", max_length=255, blank=True, null=True)
    phone_number = models.CharField("电话号码", max_length=20, blank=True, null=True)

    class Meta:
        verbose_name = "供应商"
        verbose_name_plural = "供应商"

    def __str__(self):
        return self.supplier_name

# 客户模型
class Customer(models.Model):
    customer_name = models.CharField("客户名称", max_length=255)
    contact_info = models.TextField("联系信息")
    address = models.TextField("地址", blank=True, null=True)
    phone_number = models.CharField("电话号码", max_length=20, blank=True, null=True)

    class Meta:
        verbose_name = "客户"
        verbose_name_plural = "客户"

    def __str__(self):
        return self.customer_name

# 订单模型
class Order(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, verbose_name="客户")
    order_date = models.DateTimeField("订单日期", auto_now_add=True)
    total_amount = models.DecimalField("总金额", max_digits=10, decimal_places=2)

    class Meta:
        verbose_name = "订单"
        verbose_name_plural = "订单"
    def __str__(self):
        return f"订单 {self.id} 由 {self.customer}"

# 订单详情模型
class OrderDetail(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, verbose_name="订单")
    product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name="商品")
    quantity_purchased = models.IntegerField("购买数量")
    unit_price = models.DecimalField("单价", max_digits=10, decimal_places=2)

    class Meta:
        verbose_name = "订单详情"
        verbose_name_plural = "订单详情"
    def __str__(self):
        return f"{self.quantity_purchased} 个 {self.product} 在订单 {self.order}"

# 采购记录模型
class Purchase(models.Model):
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE, verbose_name="供应商")
    purchase_date = models.DateTimeField("采购日期", auto_now_add=True)
    total_cost = models.DecimalField("总成本", max_digits=10, decimal_places=2)

    class Meta:
        verbose_name = "采购记录"
        verbose_name_plural = "采购记录"
    def __str__(self):
        return f"采购 {self.id} 来自 {self.supplier}"

# 采购详情模型
class PurchaseDetail(models.Model):
    purchase = models.ForeignKey(Purchase, on_delete=models.CASCADE, verbose_name="采购")
    product = models.ForeignKey(Product, on_delete=models.CASCADE, verbose_name="商品")
    quantity_received = models.IntegerField("接收数量")
    unit_price = models.DecimalField("单价", max_digits=10, decimal_places=2)

    class Meta:
        verbose_name = "采购详情"
        verbose_name_plural = "采购详情"
    def __str__(self):
        return f"{self.quantity_received} 个 {self.product} 在采购 {self.purchase}"

 app/admin.py

from django.contrib import admin
from .models import Category, Product, Supplier, Customer, Order, OrderDetail, Purchase, PurchaseDetail



# 定义一个内联类用于在订单详情中显示商品信息
class OrderDetailInline(admin.TabularInline):
    model = OrderDetail
    extra = 1  # 默认显示额外的1行

# 定义一个内联类用于在采购详情中显示商品信息
class PurchaseDetailInline(admin.TabularInline):
    model = PurchaseDetail
    extra = 1  # 默认显示额外的1行

# 定义Category模型的管理类
class CategoryAdmin(admin.ModelAdmin):
    list_display = ('category_name',)  # 在列表页显示的字段

# 定义Product模型的管理类
class ProductAdmin(admin.ModelAdmin):
    list_display = ('id','product_name','selling_price', 'category', 'stock_quantity')
    search_fields = ('product_name', 'id')

# 定义Supplier模型的管理类
class SupplierAdmin(admin.ModelAdmin):
    list_display = ('id','supplier_name', 'phone_number', 'address')
    search_fields = ('supplier_name', 'id')

# 定义Customer 客户模型的管理类
class CustomerAdmin(admin.ModelAdmin):
    list_display = ('customer_name', 'phone_number')
    search_fields = ('customer_name', 'id')

# 定义Order订单模型的管理类
class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'customer', 'order_date', 'total_amount')
    inlines = [OrderDetailInline]  # 使用内联类显示订单详情
    search_fields = ('id', 'customer__customer_name')

# 定义Purchase模型的管理类
class PurchaseAdmin(admin.ModelAdmin):
    list_display = ('id', 'supplier', 'purchase_date', 'total_cost')
    inlines = [PurchaseDetailInline]  # 使用内联类显示采购详情
    search_fields = ('id', 'supplier__supplier_name')

# 注册模型到admin
admin.site.register(Category, CategoryAdmin)
admin.site.register(Product, ProductAdmin)
admin.site.register(Supplier, SupplierAdmin)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Order, OrderAdmin)
admin.site.register(Purchase, PurchaseAdmin)

主urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', admin.site.urls),  # Django自带的管理界面URLs
]

 设置:settings.py

 四、输入命令 生成Django 数据库 db.sqlite3

# 生成模型转到数据库
python manage.py makemigrations
python manage.py migrate

# 创建管理员
python manage.py createsuperuser

# 可填写入:admin   email:admin@qq.com  密码:abc123456

 五、根目录 建 templates/admin

 根据 templates/admin 目录优先 打后台的网页拿过来改从而得到覆盖原先页面来改后台页面

C:\Program Files\Python312\Lib\site-packages\django\contrib\admin\templates\admin

复制到:templates/admin

\myapp\templates\admin\change_form.html

{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_modify %}

{% block extrahead %}{{ block.super }}
<script src="{% url 'admin:jsi18n' %}"></script>
<style>
  /* 对打印机进行样式设置 */
@media print {
    .no-print {
      display: none; /* 在打印时隐藏带有no-print类的元素 */
    }
    td,th, tr,table {
      border: none;
      /* padding: 15px; */
    }
    .submit-row {
      display: none;
    }
    body {
      margin: 0;
      padding: 0;
      border: none;
    }
    #site-name {
      display: none;
    }
    @page {
    margin-top: 0;
    margin-bottom: 0;
  }
  header, footer {
    display: none;
  }
  /* 或者 */
  header, footer {
    visibility: hidden;
    position: absolute;
    top: -10000px;
  }

  }
</style>
{{ media }}
{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" href="{% static "admin/css/forms.css" %}">{% endblock %}

{% block coltype %}colM{% endblock %}

{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}

{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
&rsaquo; {% if add %}{% blocktranslate with name=opts.verbose_name %}Add {{ name }}{% endblocktranslate %}{% else %}{{ original|truncatewords:"18" }}{% endif %}
</div>
{% endblock %}
{% endif %}

{% block content %}<div id="content-main">
{% block object-tools %}
{% if change and not is_popup %}
  <ul class="object-tools">
    {% block object-tools-items %}
      {% change_form_object_tools %}
    {% endblock %}
  </ul>
{% endif %}
{% endblock %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}{% if form_url %}action="{{ form_url }}" {% endif %}method="post" id="{{ opts.model_name }}_form" novalidate>{% csrf_token %}{% block form_top %}{% endblock %}
<div>
{% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %}
{% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %}
{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
{% if errors %}
    <p class="errornote">
    {% blocktranslate count counter=errors|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %}
    </p>
    {{ adminform.form.non_field_errors }}
{% endif %}

{% block field_sets %}
{% for fieldset in adminform %}
  {% include "admin/includes/fieldset.html" with heading_level=2 prefix="fieldset" id_prefix=0 id_suffix=forloop.counter0 %}
{% endfor %}
{% endblock %}

{% block after_field_sets %}{% endblock %}

{% block inline_field_sets %}
{% for inline_admin_formset in inline_admin_formsets %}
    {% include inline_admin_formset.opts.template %}
{% endfor %}
{% endblock %}

{% block after_related_objects %}{% endblock %}

{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}

<div class="submit-row">
  <button onclick="printDocument()" class="btn" style="background-color: rgb(22, 194, 247);height: 35px;width: 80px;border-radius: 5px;border: none;color: #fff;" >打印</button>
</div>

{% block admin_change_form_document_ready %}
    <script id="django-admin-form-add-constants"
            src="{% static 'admin/js/change_form.js' %}"
            {% if adminform and add %}
                data-model-name="{{ opts.model_name }}"
            {% endif %}
            async>
    </script>
{% endblock %}

{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}

</div>
</form></div>
<script>
  function printDocument() {
    window.print();
}
    </script>
</script>
{% endblock %}

用了CSS 隐藏的方法来和改变样式的 来做个用浏览器打印的方法

@media print {
    .no-print {
      display: none; /* 在打印时隐藏带有no-print类的元素 */
    }

@page {    ---------------去掉页眉 页脚
    margin-top: 0;
    margin-bottom: 0;
  }

调用浏览器来打印

<button οnclick="printDocument()"

window.print();

contine......更多的细节后面分解

运行起来

python manage.py runserver  

不想看到 下面的日志

就在settings.py 加入下面这个

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': 'general.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': False,
        },
    },
}

六、Window 下配置 Nginx

nginx.conf

 server {
        listen       80;
        server_name  localhost;

        location /static/ {
            alias E:/BIT_Web_2025/static/;  
        }
       
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }


        location /media/ {
            alias E:/BIT_Web_2025/media/; 
        }

 把admin后台 模板 html复制到 templates ,

C:\Program Files\Python312\Lib\site-packages\django\contrib\admin\templates\admin

静态 css js 之类 复制static/admin 

C:\Program Files\Python312\Lib\site-packages\django\contrib\admin\static\admin

这样后台就可以打开样式

pm2 来管理

ecosystem.config.js

module.exports = {
  apps : [{
    name: "内部测试版",
    script: "manage.py",
    args: "runserver 0.0.0.0:8000",
    instances: 1,
    autorestart: true,
    watch: false,
    max_memory_restart: "150M"
  }]
};

start_pm2.bat

@echo off
pm2 start ecosystem.config.js --no-daemon

move2.py

移动到第二个桌面

import pyautogui
import time

# # 按下 Windows 键
# pyautogui.press('win')

# # 等待一段时间,确保 Windows 键的效果生效
# time.sleep(0.2)

# # 按下 Tab 键
# pyautogui.press('tab')

# # 释放 Tab 键
# pyautogui.keyUp('tab')

# # 释放 Windows 键
# pyautogui.keyUp('win')

time.sleep(10)

# 模拟 Ctrl+C (复制)
pyautogui.keyDown('win')
pyautogui.press('tab')
# 释放 Tab 键
pyautogui.keyUp('tab')

# 释放 Windows 键
pyautogui.keyUp('win')

# 移动鼠标到指定位置
# pyautogui.moveTo(566, 366, duration=1) # 1秒内移动到(200, 200)

# 按下并释放鼠标右键
# pyautogui.mouseDown(button='right')
# pyautogui.mouseUp(button='right')

# 模拟按下 Tab 键两次
pyautogui.press('tab')
time.sleep(1)
pyautogui.press('tab')
# 模拟按下并释放向下箭头键三次
# for _ in range(2):
#     pyautogui.keyDown('down')
#     time.sleep(0.3)  # 等待0.1秒,模拟按键持续时间
#     pyautogui.keyUp('down')

# 模拟按下并释放向右箭头键一次
pyautogui.keyDown('right')
time.sleep(0.3)  # 等待0.1秒,模拟按键持续时间
# pyautogui.keyUp('right')

# 移动鼠标到期望点击的位置(这里需要你根据实际情况指定坐标)
# 假设我们移动到屏幕中心位置点击
# pyautogui.moveTo(pyautogui.size().width / 2, pyautogui.size().height / 2)

# 模拟按下并释放 'Enter' 键
pyautogui.press('enter')

# 移动鼠标到指定位置
# pyautogui.moveTo(100, 100, duration=1) # 1秒内移动到(200, 200)

# 执行鼠标点击
# pyautogui.click()  # 默认点击当前鼠标位置
time.sleep(1)

pyautogui.keyDown('left')
time.sleep(1)
pyautogui.press('enter')

Onekey.py

同时打开两个程序,不用等上一个结束

import subprocess


# pm2 start ecosystem.config.js --no-daemon
# 使用subprocess.Popen在后台运行第一个命令
# process1 = subprocess.Popen(["python", "manage.py", "runserver", "0.0.0.0:8000"])
process1 = subprocess.Popen('start_pm2.bat')

# 立即运行第二个命令
subprocess.run(["python", "move2.py"])

七、外网 穿透

Onekey-net.py

打开 

复制 外网 网址

写入 语雀 笔记 (打开小记录入网址) 方便外网 穿透!!!

import pyautogui
import time



def Cpolar():
    # 移动鼠标到指定位置
    pyautogui.moveTo(x=1860, y=640)  #  # 第5个位置nas
    
    # 双击鼠标
    pyautogui.doubleClick()

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(3)

    # 模拟按下Tab键
    pyautogui.press('tab')

    # 输入第一段文本内容
    pyautogui.write('账号')

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(3)

    # 模拟按下Enter键
    pyautogui.press('enter')

    # 再次模拟按下Tab键
    pyautogui.press('tab')

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(1)

    # 输入第二段文本内容
    pyautogui.write('密码')

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(1)

    # 再次模拟按下Tab键
    pyautogui.press('tab')
    # 模拟按下Enter键
    pyautogui.press('enter')


    # 移动鼠标到指定位置
    pyautogui.moveTo(x=69, y=249)  #  # 第3个菜单位

    time.sleep(1)

    # 单击鼠标
    pyautogui.click()

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(2)

    # 移动鼠标到指定位置
    pyautogui.moveTo(x=111, y=303)  #  # 第3个菜单位

    # 单击鼠标
    pyautogui.click()

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(3)

    # 假设你想要选择的区域的左上角和右下角坐标如下
    left_top_x, left_top_y = 631, 279  # 左上角坐标
    right_bottom_x, right_bottom_y = 868, 313  # 右下角坐标

    # 移动鼠标到左上角位置
    pyautogui.moveTo(left_top_x, left_top_y)
    # 按下鼠标左键开始选择
    pyautogui.mouseDown()

    # 移动鼠标到右下角位置
    pyautogui.moveTo(right_bottom_x, right_bottom_y)
    # 释放鼠标左键完成选择
    pyautogui.mouseUp()

    # 模拟按下 Ctrl+C 进行复制
    pyautogui.hotkey('ctrl', 'c')


    print('关闭浏览器')
    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(1)   

     # 移动鼠标到指定位置
    pyautogui.moveTo(x=1896, y=16)  #  关闭浏览器

    # 单击鼠标
    pyautogui.click()

    print('打开网络笔记')
    # 等待5秒,给你时间切换到需要操作的窗口 笔记
    time.sleep(1)
    # 移动鼠标到指定位置
    pyautogui.moveTo(x=1865, y=735)  #  # 第3个菜单位
    # 双击鼠标
    pyautogui.doubleClick()

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(8)
    # 按下 Ctrl + Shift + Y 打开命令面板
    pyautogui.hotkey('ctrl', 'shift', 'y')

    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(2)
    # 按下 Ctrl + v 粘贴内容
    pyautogui.hotkey('ctrl', 'v')
    # 按下回车键
    pyautogui.press('enter')
    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(13)
    # 转换到需要操作的按钮上
    pyautogui.moveTo(x=1190, y=610)  #  # 第3个菜单位
    # 单击鼠标
    pyautogui.click()
    # 等待5秒,给你时间切换到需要操作的窗口
    time.sleep(1)
    # 移动鼠标到指定位置
    pyautogui.moveTo(x=1696, y=119)  #  关闭笔记
    # 单击鼠标
    pyautogui.click()





time.sleep(2)
Cpolar()
print('复制网址已完成')

八、Windows 配

在Windows 11上使用WSGI部署Django应用程序,你可以选择使用Waitress作为WSGI服务器,因为它兼容Windows环境。以下是部署步骤:

1. 安装Waitress

首先,确保你已经安装了Waitress。你可以使用pip进行安装:


bash

取消自动换行

复制

pip install waitress

2. 准备你的Django项目

确保你的Django项目已经设置好,并且可以正常运行。你需要知道Django项目的wsgi.py文件的位置,它通常位于你的Django应用目录下。

3. 创建一个启动脚本

创建一个Python脚本(例如runserver.py),用于启动Waitress服务器。脚本内容可能如下:


python

取消自动换行

复制

from waitress import serve
from myproject.wsgi import application  # 替换为你的Django项目名

if __name__ == "__main__":
    serve(application, host='localhost', port=8000)

确保替换myproject.wsgi.application为你的Django项目的WSGI应用实例。

4. 运行Waitress服务器

在命令行中运行你刚才创建的脚本:


bash

取消自动换行

复制

python runserver.py

这将启动Waitress服务器,并在本地的8000端口上监听。

5. 测试你的Django应用

现在,你应该可以通过浏览器访问http://localhost:8000来查看你的Django应用是否正常运行。

6. 配置Web服务器(可选)

虽然Waitress可以作为独立服务器运行,但在生产环境中,你可能希望使用Web服务器(如IIS或Nginx)作为反向代理服务器。对于IIS,你可以使用wfastcgi模块来运行Python应用程序。对于Nginx,你可以配置它来代理请求到Waitress服务器。

7. 部署到生产环境

部署到生产环境时,你可能需要考虑以下因素:

  • 使用更健壮的服务器配置(如使用多个工作进程)。
  • 设置日志记录和错误处理。
  • 使用HTTPS。
  • 设置防火墙和安全组规则。
  • 监控和自动重启机制。

总结

虽然在Windows上部署Django不如在Unix-like系统上那么常见,但通过使用Waitress这样的纯Python WSGI服务器,你仍然可以轻松地在Windows 11上部署和运行你的Django Web应用程序。确保在部署过程中考虑到性能和安全的最佳实践。

要隐藏命令窗口运行Waitress服务,通常有几种方法:

1. **使用批处理文件**:在Windows系统中,你可以创建一个批处理文件(`.bat`),在该文件中启动Waitress服务,并且使用`start`命令来运行,这样就不会显示命令窗口。例如:
   ```bat
   @echo off
   start /B python -m waitress --listen=*:8080 myapp:app
   ```
   这里`/B`选项表示不创建新的命令行窗口。

2. **使用任务计划程序**:你可以使用Windows的任务计划程序来启动Waitress服务,并且设置为隐藏运行。

3. **使用专业软件**:有些软件如`NSSM`(Non-Sucking Service Manager)可以帮助你将Waitress服务设置为后台运行。

4. **使用Python脚本**:在Python脚本中使用`subprocess`模块启动Waitress服务,并且设置`creationflags`参数为`subprocess.CREATE_NO_WINDOW`来隐藏命令窗口。

runserver.py

from waitress import serve
from BitSite.wsgi import application  # 替换为你的Django项目名

if __name__ == "__main__":
    serve(application, host='localhost', port=8000)

run.py

import subprocess

# Waitress服务的启动命令
command = [
    'waitress-serve', '--listen=*:8000', 'runserver:application'
]

# 使用subprocess.Popen启动Waitress服务,隐藏命令窗口
process = subprocess.Popen(command, creationflags=subprocess.CREATE_NO_WINDOW)

# 等待服务启动(可选,根据需要)
process.wait()

结束可找进程,直接结束

 

5. **使用服务包装器**:将你的Python应用程序包装成一个Windows服务,例如使用`pywin32`库中的`win32serviceutil`模块。

请注意,隐藏命令窗口通常用于生产环境,以提高用户体验和安全性。在开发环境中,通常不建议隐藏命令窗口,因为这样可以更容易地查看日志和调试信息。

八、 后台 内联显示(Inline Display) 

参考例:

models.py

from django.db import models


class ComponentCategory(models.Model):
    category_id = models.AutoField(primary_key=True, verbose_name="类别ID")
    category_name = models.CharField(max_length=50, verbose_name="类别名称")
    category_description = models.TextField(verbose_name="类别描述")
    def __str__(self):
        return self.category_name 
    class Meta:
        verbose_name = "类别"
        verbose_name_plural = verbose_name


class Component(models.Model):
    component_id = models.AutoField(primary_key=True, verbose_name="配件ID")
    category_id = models.ForeignKey(ComponentCategory, on_delete=models.CASCADE, verbose_name="分类ID")
    component_name = models.CharField(max_length=100, verbose_name="配件名称")
    purchase_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="采购价格")
    selling_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="销售价格")
    description = models.TextField(verbose_name="描述")
    def __str__(self):
        return self.component_name
    class Meta:
        verbose_name = "配件"
        verbose_name_plural = verbose_name


class User(models.Model):
    user_id = models.AutoField(primary_key=True, verbose_name="客户ID")
    username = models.CharField(max_length=50, verbose_name="客户名")
    password = models.CharField(max_length=255, verbose_name="密码")
    email = models.CharField(max_length=100, verbose_name="邮箱")
    def __str__(self):
        return self.username
    class Meta:
        verbose_name = "客户"
        verbose_name_plural = verbose_name


class ComputerConfiguration(models.Model):
    config_id = models.AutoField(primary_key=True, verbose_name="配置ID")
    user_id = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户ID")
    config_name = models.CharField(max_length=100, verbose_name="配置名称")
    creation_date = models.DateTimeField(auto_now_add=True, verbose_name='创建日期', blank=True, null=True)
    def __str__(self):
        return self.config_name
    class Meta:
        verbose_name = "组装电脑"
        verbose_name_plural = verbose_name


class ConfigurationComponent(models.Model):
    config_component_id = models.AutoField(primary_key=True, verbose_name="配置组件ID")
    config_id = models.ForeignKey(ComputerConfiguration, on_delete=models.CASCADE, verbose_name="配置ID")
    component_id = models.ForeignKey(Component, on_delete=models.CASCADE, verbose_name="组件ID")
    quantity = models.IntegerField(verbose_name="数量")
    selling_price_generated = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="生成售价")
    def __str__(self):
        return self.config_id.config_name + " - " + self.component_id.component_name
    class Meta:
        verbose_name = "配件单价"
        verbose_name_plural = verbose_name

admin.py

from django.contrib import admin
from.models import ComponentCategory, Component, User, ComputerConfiguration, ConfigurationComponent


class ConfigurationComponentInline(admin.TabularInline):
    model = ConfigurationComponent
    fields = ('component_id', 'quantity', 'selling_price_generated')
    classes = ('grp-collapse',)
    extra = 1


class ComputerConfigurationAdmin(admin.ModelAdmin):
    inlines = [ConfigurationComponentInline]
    def total_selling_price(self, obj):
        components = ConfigurationComponent.objects.filter(config_id=obj.config_id)
        total = sum([component.selling_price_generated * component.quantity for component in components])
        return total

    total_selling_price.short_description = '合计销售价格'
    list_display = ('config_id', 'user_id', 'config_name','creation_date', 'total_selling_price' )
    list_display_links = ('config_name',)

    search_fields = ('config_name',)
    list_per_page = 4

class ComponentCategoryAdmin(admin.ModelAdmin):
    list_display = ('category_id', 'category_name', 'category_description')
    list_display_links = ('category_name',)

admin.site.register(ComponentCategory, ComponentCategoryAdmin)


@admin.register(Component)
class ComponentAdmin(admin.ModelAdmin):
    list_display = ('component_id', 'category_id', 'component_name', 'purchase_price', 'selling_price', 'description')
    list_display_links = ('component_name',)

    search_fields = ('component_name',)
    list_per_page = 4
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    list_display = ('user_id', 'username', 'password', 'email')
    list_display_links = ('username',)

admin.site.register(ComputerConfiguration, ComputerConfigurationAdmin)
@admin.register(ConfigurationComponent)
class ConfigurationComponentAdmin(admin.ModelAdmin):
    list_display = ('config_component_id', 'config_id', 'component_id', 'quantity', 'selling_price_generated')
    list_display_links = ('config_component_id',)
    search_fields = ('config_component_id',)
    list_per_page = 4