一、前置条件:
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>
› <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
› {% if has_view_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
› {% 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,
},
},
}