当前位置:首页 > 新闻动态 > 网站文章

许昌鲤鱼IT编程教育带你用Python开发企业门户网站(前端+后端)

来源: 浏览:310 时间:2023-08-16

人生苦短,为什么我要用python?

  • 首先让我们来看一个2019年最新的编程语言权威排行榜github octoverse
  • 既然python如此流行,谁能告诉我why?易上手跨平台高薪水应用广TIPpython除了不能生孩子,啥都能干,如WEB开发,网络爬虫,数据分析,大数据,人工智能,服务器运维,自动化测试...

#实战目标

使用Python3.7+Django2.2+sqlite实现一个企业门户网站先睹为快

TIP

该网站能满足大多数企业门户网站的需求

#学习前提

  • 对编程感兴趣
  • 了解python的基础语法
  • 了解html/css/js

#环境搭建

#编程语言python3.7

  • windows环境下载安装包执行下载的安装包,注意在安装时选中Add Python 3.7 to PATH



Mac环境

  • 下载安装文件
  • 执行下载的安装包
  • 配置

在~/.bash_profile 文件中添加如下配置


IDE pycharm专业版

  • windows环境下载pycharm Professional 安装包






  • Mac环境下载pycharm Professional 安装包
  • #虚拟环境 virtualenvwrapper

    虚拟环境的主要作用是给不同的项目创建独立的运行环境,每一个虚拟环境可以有自己版本的依赖包

    • Windows 安装在命令行执行

    新建WORKON_HOME系统变量,值为一个有效的路径,用了存放虚拟环境





    TIP

    打开控制面板-系统和安全-系统-高级系统设置-环境变量-系统变量-点击新建

    • 双击python的安装路径Scripts irtualenvwrapper.bat文件


    以管理员身份重新打开命令行


    Mac 安装

    • 在终端执行以下命令


    使用


    初始化项目

    #创建项目的虚拟环境


    用pycharm新建django项目

    • 在新建面板的左侧选择django项目
    • 在Location中指定项目所在的位置
    • 在Existing interpreter 中指定项目的python解释器在Virtualenv Environment中的Interpreter 中选择创建的虚拟环境python所在的路径TIP一般Windows用的这个路径为 虚拟环境存放目录虚拟环境名称Scriptspython.exe一般Mac用户的这个路径为 用户名/.virtualenvs/虚拟环境名称/bin/python
    • 选中Enable Django admin


  • 打开 Run->Run 'project' 运行项目来测试django是否安装成功
  • django 参考文档: Djano 官网 Djano 中文文档
  • #完善项目目录结构

    • 在项目目录下新建media文件夹用来存放上传资源
    • 在项目目录下新建static文件夹用来存放静态资源
    • 在项目目录下新建apps包用来存放应用

    #pycharm 创建django应用

    • 打开 Tools->Run manage.py task
    • 在终端执行


    django项目目录结构解析


    WEB原理解析和MVC介绍

    #WEB原理解析


  • 客户端用户发送请求
  • 服务器解析请求,计算数据并返回给客户端
  • 客户端解析返回的数据
  • #MVC介绍



  • 客户端用户发送请求
  • 模型框架负责路由解析,根据路由寻找对应的控制器(Controller)和行为(action)
  • 行为(action)调用相关的模型(Model)进行数据操作
  • 行为(action)根据数据操作的结果调用视图(View)进行页面的渲染,输出到客户端
  • #静态页面路由配置

    #添加View类

    在apps.basic.views添加处理路由的View


    TIP

    Django中view分为CBV(class base view)和FBV(function base view),推荐CBV

    #添加html页面

    在templates文件夹新新建一个index.html静态页面

    #配置路由

    在urls.py文件中添加


    静态资源处理

    #在html页面中使用静态资源

    copy前端准备好的模版文件(html)到templates文件夹中

    #添加静态资源

    copy前端准备好的静态资源文(css,js,image)件到static文件中

    #配置静态文件查找路径配置

    在settings.py中添加如下配置


    模版的使用

    #定义模版


    配置其他路由和跳转

    #View类


    配置路由


    TIP

    注意detail路由的配置是为了传递参数到view中

    #配置跳转

    • 直接跳转


    记录导航选中状态

    • 在view中传递当前页面标识到模版


    在模版中根据标识设置class

  • 首页
  • 产品
  • 动态
  • 关于
  • #模型定义

    安装Pillow

    由于模型中需要定以图片的上传,所以需要安装

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

    定义共同父类

    from datetime import datetime
    from django.db import models
    # 定义共同类
    class BaseModel(models.Model):
     add_time = models.DateTimeField(verbose_name="添加时间",default=datetime.now)
     class Meta:
     abstract = True #不生成表

    定义站点配置模型

    class Config(BaseModel):
     name = models.CharField(verbose_name="站点名称", max_length=100)
     logo = models.ImageField(verbose_name="站点logo", max_length=300, upload_to="config/logo/%Y/%m")
     url = models.CharField(verbose_name="站点连接", max_length=100)
     wx_qr_code = models.ImageField(verbose_name="微信二维码",max_length=300,upload_to="config/wx/%Y/%m")
     tel = models.CharField(verbose_name="联系电话",max_length=20)
     hours = models.CharField(verbose_name="营业时间", max_length=40)
     mail = models.CharField(verbose_name="电子邮件", max_length=300)
     icp = models.CharField(verbose_name="备案号", max_length=50)
     class Meta:
     verbose_name = "站点配置"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.name

    数据库表操作和创建管理员

    • 打开Tools->Run manage.py task
    • 生成表迁移
    makemigrations
    
    • 将表迁移同步到数据库
    migrate
    
    • 创建超级用户
    createsuperuser

    后台管理配置

    #注册模型

    在应用的admin.py文件中

    #admin.py
    from django.contrib import admin
    from apps.basic.models import Config
    class ConfigAdmin(admin.ModelAdmin):
     pass
    admin.site.register(Config,ConfigAdmin)
    

    #配置中文和时区

    在settings.py中配置中文和时区

    #settings.py
    LANGUAGE_CODE = 'zh-hans'
    TIME_ZONE = 'Asia/Shanghai'
    USE_TZ = False
    

    #修改网页title和站点header

    在应用的admin.py文件中

    #admin.py
    #修改网页title和站点header
    admin.site.site_title = "PyCMS后台管理"
    admin.site.site_header = "PyCMS"
    

    #修改应用的中文名称

    在应用的apps.py文件中修改应用的中文名称

    #apps.py
    class BasicConfig(AppConfig):
     name = 'apps.basic'
     verbose_name = "站点基本"
    

    #配置上传资源路径

    在settings.py中配置上传资源路径

    #settings.py
    MEDIA_URL = "/media/"
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    #自定义表单

    在应用的admin.py文件中,在管理器类中添加 fields 属性来定义表单要显示的字段

    #admin.py
    from django.contrib import admin
    from apps.basic.models import Config
    class ConfigAdmin(admin.ModelAdmin):
     fields = ('name','logo','url','wx_qr_code','tel','hours','mail','icp')
    # Register your models here.
    admin.site.register(Config,ConfigAdmin)
    

    #列表显示

    在应用的admin.py文件中,在管理器类中添加 list_display 属性来定义列表要显示的字段

    #admin.py
    from django.contrib import admin
    from apps.basic.models import Config
    class ConfigAdmin(admin.ModelAdmin):
     fields = ('name','logo','url','wx_qr_code','tel','hours','mail','icp')
     list_display = ('name','url','tel','hours','mail','icp')
    # Register your models here.
    admin.site.register(Config,ConfigAdmin)

    admin登陆添加验证码

    • 安装依赖
    pip3 install django-multi-captcha-admin
    pip3 install django-simple-captcha
    
    • 配置
    #settings.py
    INSTALLED_APPS = [
     'multi_captcha_admin',#需要在django.contrib.admin前添加
     ....
     'captcha',#验证码模块
    ]
    MULTI_CAPTCHA_ADMIN = {
     'engine': 'simple-captcha',
    }
    
    • 添加路由
    #urls.py
    from django.urls import path, include
    ...
    url(r'^captcha/', include('captcha.urls')),
    
    • 数据迁移
    migrate
    

    #分配数据到模版展示

    #获取和分配数据(objects.get()获取一条)

    # views.py
    from apps.basic.models import Config
    class IndexView(View):
     def get(self, request, *args, **kwargs):
     # 获取一条数据对象
     config = Config.objects.get()
     return render(request, 'index.html',{
     'currentPage':'index',
     'config':config #将对象分配到模版
     })
    

    #展示数据

    • 普通数据展示
    
    

    {{ config.tel }}({{ config.hours }})

    • 上传图片数据展示模版中使用
      在urls.py中配置上传文件请求路由# urls.py from django.views.static import serve from project.settings import MEDIA_ROOT urlpatterns = [ ... # 上传文件访问的路由配置 url(r'^media/(?P.*)$', serve, {"document_root": MEDIA_ROOT}), ]

    友情连接

    #模型定义

    class Link(BaseModel):
     name = models.CharField(verbose_name="友情连接名称", max_length=100)
     url = models.CharField(verbose_name="友情连接地址", max_length=300)
     class Meta:
     verbose_name = "友情连接"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.name
    

    TIP

    模型注册,表迁移,数据同步参考站点配置模型

    #获取和分配数据(objects.all()获取所有)

    #views.py
    class IndexView(View):
     def get(self, request, *args, **kwargs):
     # 获取一条数据对象
     config = Config.objects.get()
     # 获取友情链接
     links = Link.objects.all()
     return render(request, 'index.html',{
     'currentPage':'index',
     'config':config, #将对象分配到模版
     'links':links
     })
    

    #展示数据

    
    {% for link in links %}
    {{ link.name }}
    {% endfor %}
    

    TIP

    Link.objects.all()返回的是一个QuerySet,需要在模版中通过for in来遍历得到每一对象

    #首页轮播图

    #模型定义

    class Carousel(BaseModel):
     title = models.CharField(verbose_name="轮播图名称", max_length=100)
     image = models.ImageField(verbose_name="轮播图图片", max_length=300, upload_to="carousel/%Y/%m")
     desc = models.CharField(verbose_name="轮播图描述", max_length=100)
     class Meta:
     verbose_name = "首页轮播图"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.title
    

    TIP

    模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型

    #产品

    #模型定义

    class Product(BaseModel):
     name = models.CharField(verbose_name="产品名称", max_length=100)
     desc = models.TextField(verbose_name="产品描述", max_length=300)
     icon = models.ImageField(verbose_name="产品图标", max_length=300, upload_to="product/icon/%Y/%m")
     url = models.CharField(verbose_name="产品连接", max_length=100)
     image = models.ImageField(verbose_name="产品封面",max_length=300,upload_to="product/post/%Y/%m")
     is_show_index = models.BooleanField(verbose_name="是否显示在首页",default=False)
     class Meta:
     verbose_name = "产品"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.name
    

    #数据获取(filter筛选)

    #views.py
    # 获取首页需要的产品
    products = Product.objects.filter(is_show_index=True)
    

    TIP

    • 模型注册,表迁移,数据同步,分配数数据,展示数据 参考友情链接模型
    • 数据获取使用filter进行筛选,filter返回结果也是一个QuerySet,在模版中需要用for in

    #服务

    #模型定义

    # 服务
    class Service(BaseModel):
     name = models.CharField(verbose_name="服务名称", max_length=100)
     desc = models.TextField(verbose_name="服务描述", max_length=300)
     image = models.ImageField(verbose_name="服务封面",max_length=300,upload_to="service/post/%Y/%m")
     class Meta:
     verbose_name = "服务"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.name
    

    TIP

    模型注册,表迁移,数据同步,获取和分配数数据,展示数据 参考友情链接模型

    #产品页面开发

    TIP

    参考首页开发

    #动态页面开发

    #动态模型

    class News(BaseModel):
     name = models.CharField(verbose_name="动态标题", max_length=100)
     desc = models.TextField(verbose_name="动态描述", max_length=300)
     intro = models.TextField(verbose_name="动态简介", max_length=300)
     content = models.TextField(verbose_name="动态内容", max_length=300)
     read_nums = models.IntegerField(verbose_name="阅读人数", default=0)
     post = models.ImageField(verbose_name="封面图片",max_length=300,upload_to="news/post/%Y/%m")
     image = models.ImageField(verbose_name="详情图片", max_length=300, upload_to="news/detail/%Y/%m")
     class Meta:
     verbose_name = "动态"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.name
    

    #安装分页应用

    • 参考 django-pure-pagination
    • 在虚拟环境中安装
    pip3 install django-pure-pagination
    
    • 在settings.py中INSTALLED_APPS配置
    #settings.py
    INSTALLED_APPS = [
     ...
     'pure_pagination',#分页配置
    ]
    
    • 在settings.py中配置分页参数
    #settings.py
    # 分页相关配置
    PAGINATION_SETTINGS = {
     'PAGE_RANGE_DISPLAYED': 6,
     'MARGIN_PAGES_DISPLAYED': 2,
     'SHOW_FIRST_PAGE_WHEN_INVALID': True,
    }
    

    #在views.py中使用分页应用

    from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
    class NewsView(View):
     def get(self, request, *args, **kwargs):
     # 获取一条数据对象
     config = Config.objects.get()
     # 获取友情链接
     links = Link.objects.all()
     # 按添加时间倒序获取所有的动态
     all_news = News.objects.order_by("-add_time")
     try:
     page = request.GET.get('page', 1)
     except PageNotAnInteger:
     page = 1
    p = Paginator(all_news, per_page=2, request=request)
    news = p.page(page)
     return render(request, 'news.html',{
     'currentPage': 'news',
     'config': config,
     'links': links,
     'news':news
     })
    

    TIP

    • objects.order_by()是排序
    • 以上代码生成的news是一个分页对象

    #在模版中使用分页

    • 动态遍历

    TIP

    分页对象需要遍历对象上的object_list

    • 分页器渲染
     
    {% if news.has_previous %} 上一页 {% endif %} {% for page in news.pages %} {% if page %} {% ifequal page news.number %} {{ page }} {% else %} {{ page }} {% endifequal %} {% else %} ... {% endif %} {% endfor %} {% if news.has_next %} 下一页 {% endif %}

    #动态详情页面开发

    #获取动态并分配给模版

    class NewsDetailView(View):
     def get(self, request,news_id, *args, **kwargs):
     # 获取一条数据对象
     config = Config.objects.get()
     # 获取友情链接
     links = Link.objects.all()
     # 获取动态
     news = News.objects.get(id=int(news_id))
     # 修改动态的阅读人数
     news.read_nums += 1
     news.save()
    return render(request, 'newsDetail.html',{
     'currentPage': 'news',
     'config': config,
     'links': links,
     'news':news
     })
    

    TIP

    • objects.get(id=int(news_id))是根据id获取数据
    • 模版数据展示参考之前模型

    #关于我们页面开发

    #定义模型

    # 公司简介
    class Intro(BaseModel):
     content = models.TextField(verbose_name="简介内容", max_length=300)
     image = models.ImageField(verbose_name="简介图片", max_length=300, upload_to="intro/%Y/%m")
     class Meta:
     verbose_name = "公司简介"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.content
    # 发展历程
    class Timeline(BaseModel):
     label = models.CharField(verbose_name="历程标签", max_length=100)
     desc = models.TextField(verbose_name="历程描述", max_length=100)
     image = models.ImageField(verbose_name="历程图片", max_length=300, upload_to="timeline/%Y/%m")
     class Meta:
     verbose_name = "发展历程"
     verbose_name_plural = verbose_name
     def __str__(self):
     return self.label
    

    TIP

    模型注册,表迁移,数据同步,获取和分配数数据, 参考友情链接模型

    #数据展示

    {% for intro in intros %}
     {% if forloop.counter|divisibleby:2 %}
     

    {{ intro.content }}

    {{ intro.content }}

    {% else %}

    {{ intro.content }}

    {% endif %} {% endfor %}

    TIP

    • 在模版中遍历时可以用{% if forloop.counter|divisibleby:2 %}来判断当前是否是偶数
    • 成长历程的遍历同理

    #配置错误页面

    #准备相关的错误页面

    • 404.html

    #修改settings.py文件

    # 开发环境配置
    # DEBUG = True
    # ALLOWED_HOSTS = []
    # 线上环境配置
    DEBUG = False
    ALLOWED_HOSTS = ['*']
    # 开发环境配置,静态文件查找路径配置
    # STATICFILES_DIRS = [
    # os.path.join(BASE_DIR, 'static'),
    # ]
    # 线上环境配置
    STATIC_ROOT = os.path.join(BASE_DIR, 'static')
    

    #修改urls.py文件

    from project.settings import STATIC_ROOT
    urlpatterns = [
     ...
     # 静态资源访问的路由配置(线上配置only)
     url(r'^static/(?P.*)$', serve, {"document_root": STATIC_ROOT}),
    ]
    

    #收集项目所需依赖文件

    pip3 freeze > requirements.txt
    

    #部署上线

    #购买云服务器(以阿里云为例)

    • 购买时操作系统选择CentOS 7.7 64位
    • 记录远程连接密码,在远程连接时用
    • 重置实例密码,该密码是登陆系统时使用

    #开放云服务器的端口

    在云服务器对应的实例中安全组规则中添加

    允许	自定义 TCP	80/80	 IPv4地址段访问	0.0.0.0/0 
    允许	自定义 TCP	8000/8000	IPv4地址段访问	0.0.0.0/0 
    

    #登陆服务器

    • 方法一:远程连接后登陆系统,用户名:root 密码:重置的实例密码
    • 方法二(推荐):在本机终端通过 ssh root@服务器公共ip 登陆,登陆需要输入实例密码,注意windows用户需要安装xshell

    #用pycharm上传代码

    • Tools->Deployment->Configuration...
    • Add->SFTP
    • 配置Connection连接远程服务器
    • 配置Mappings,本地项目的文件和远程服务的目录对应,注意远程服务器的目录需要自己建立
    • 右击需要上传的项目目录->deployment->upload,注意如果只上传某一个文件或目录则只右击需要上传的文件或者目录

    #环境安装

    #安装python3.7

    • 1.安装依赖
    yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel gcc gcc-c++ openssl-devel libffi-devel python-devel mariadb-devel
    
    • 2.下载源码
    wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz 
    tar -xzvf Python-3.7.3.tgz -C /tmp 
    cd /tmp/Python-3.7.3/ 
    
    • 3.把Python3.7安装到 /usr/local 目录
    ./configure --prefix=/usr/local
    make
    make install #这一步比较耗时
    
    • 4.更改/usr/bin/python链接
    ln -s /usr/local/bin/python3.7 /usr/bin/python3
    ln -s /usr/local/bin/pip3.7 /usr/bin/pip3
    

    #安装新版sqlite

    • 1.下载源码
    wget https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz
    tar -zxvf sqlite-autoconf-3270200.tar.gz -C /tmp 
    cd /tmp/sqlite-autoconf-3270200/ 
    
    • 2.把sqlite安装到 /usr/local 目录
    ./configure --prefix=/usr/local
    make
    make install #这一步比较耗时
    
    • 3.建立软链接
    #如果文件已经存在则备份
    mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
    #建立软链接
    ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
    
    • 4.修改 ~/.bashrc文件
    export LD_LIBRARY_PATH="/usr/local/lib"
    
    • 5.从新加载~/.bashrc文件
    source ~/.bashrc
    

    #安装virtualenvwrapper

    • 1.安装
    export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
    yum install python-setuptools python-devel
    pip3 install virtualenvwrapper
    
    • 2.修改~/.bashrc文件
    export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
    export WORKON_HOME=$HOME/.virtualenvs
    source /usr/local/bin/virtualenvwrapper.sh
    
    • 3.从新加载~/.bashrc文件
    source ~/.bashrc
    

    TIP

    如果出现找不到文件,可以使用以下命令查找文件的位置

    sudo find / -name 文件名
    
    • 4.新建虚拟环境
    mkvirtualenv -p python3 pycms
    
    • 5.进入虚拟环境
    workon pycms
    
    • 6.安装pip包

    注意,需要把requirements.txt文件上传到服务器之后运行

    pip3 install -r requirements.txt
    
    • 7.拉取所有需要的static file 到同一个目录

    确保settings.py文件中有以下配置

    STATIC_ROOT = os.path.join(BASE_DIR, "static/")
    

    然后运行命令

    python3 manage.py collectstatic
    
    • 8.启动项目

    在项目的根目录下执行

    python3 manage.py runserver 0.0.0.0:80
    
    • 9.通过公网ip地址访问项目

    #域名解析

    设置记录类型为A,设置记录值为对应的外网ip

    #uwsgi+nignx部署项目

    #安装uwsgi

    web 容器,拉起项目

    • 1.安装
    pip3 install uwsgi
    
    • 2.测试

    在项目的根目录运行

    #项目名称.wsgi
    uwsgi --http :8000 --module project.wsgi
    
    • 3.配置

    新建 项目根目录/config/uwsgi.ini

    # uwsgi.ini file
    [uwsgi]
    # 表示需要操作的目录,也就是项目的目录
    chdir = /root/pycms
    # Django的wsgi file
    # wsgi文件的路径,名称和项目的应用名称一直
    module = project.wsgi
    # process-related settings
    # master
    master = true
    # maximum number of worker processes
    # 进程数
    processes = 10
    # the socket (use the full path to be safe)
    socket = 127.0.0.1:8000
    # chmod-socket = 664
    # clear environment on exit
    vacuum = true
    # 虚拟环境的目录
    virtualenv = /root/.virtualenvs/pycms
    # 运行log存放文件
    logto = /tmp/uwsgi.log
    
    • 4.启动uwsgi
    workon pycms
    # -d表示后台运行
    uwsgi -d -i 项目根目录/config/uwsgi.ini
    
    • 5.查看启动
    ps aux|grep uwsgi
    

    TIP

    注意:用配置文件启动的uwsgi不能直接在浏览器中访问

    • 6.查看端口
    netstat -lpnt
    
    • 6.关闭uwsgi
    killall -9 uwsgi
    

    #安装nginx

    nginx主要用来反向代理,端口转发

    • 1.安装
    sudo yum install epel-release
    sudo yum install nginx
    
    • 2.启动
    sudo systemctl start nginx
    
    • 3.新建 项目根目录/config/nginx.conf
    # the upstream component nginx needs to connect to
    upstream django {
    server 127.0.0.1:8000; #转发到的端口,同uwsig配置的端口一直
    }
    # configuration of the server
    server {
    # 监听的端口
    listen 80;
    # 域名或者ip地址,如果共存用空格隔开
    server_name 你的ip地址; 
    charset utf-8;
    # 上传文件大小设置
    client_max_body_size 75M; 
    location /media {
     alias 项目根目录/media; # 指向django的media目录
    }
    location /static {
     alias 项目根目录/static; # 指向django的static目录
    }
    # 非静态资源请求转发到django
    location / {
     uwsgi_pass django;
     include uwsgi_params; # the uwsgi_params file you installed
    }
    }
    
    • 4.将该配置文件加入到nginx的启动配置文件中
    sudo ln -s pycms_nginx.conf /etc/nginx/conf.d/
    
    • 修改 /etc/nginx/nginx.conf
    user root
    
    • 6.启动nginx
    sudo systemctl start nginx
    
    • 7.重启nigx
    sudo systemctl restart nginx
    

    #附录:pycharm常用调试技巧

    • 在需要调试的代码对应的行号处单击设置断点
    • 右键以debug模式运行代码,代码会暂停在端点处,常见调试按钮F8(第二个按钮) 执行下一步F7(第三个按钮) 进入函数内部Shift+F8(第六个按钮) 跳出函数option + F9(最后一个按钮) 直接跳转到下一个断点处


    地址 · ADDRESS

    地址:建邺区新城科技园嘉陵江东街18号2层

    邮箱:309474043@qq.Com

    点击查看更多案例

    联系 · CALL TEL

    400-8793-956

    售后专线:025-65016872

    业务QQ:309474043    售后QQ:1850555641

    ©南京安优网络科技有限公司 版权所有   苏ICP备12071769号-4  网站地图