前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【玩转全栈】----靓号管理系统实现

【玩转全栈】----靓号管理系统实现

作者头像
用户11404404
发布2025-02-02 22:35:46
发布2025-02-02 22:35:46
6700
代码可运行
举报
文章被收录于专栏:Edward的专栏Edward的专栏
运行总次数:0
代码可运行

数据库设置

新建一个数据库(或者就用之前部门、用户管理的也行),用Django连接到数据库:

代码语言:javascript
代码运行次数:0
复制
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "mydata_1",
        "USER": "root",
        "PASSWORD": "您的密码",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    }
}

新建数据库,在models中新建数据表,定义表的结构:

代码语言:javascript
代码运行次数:0
复制
from django.db import models

# Create your models here.
class Vanitynumber(models.Model):
    mobile = models.CharField(verbose_name="手机号",max_length=11, unique=True)
    price = models.IntegerField(verbose_name="价格",default=0)
    # 默认为空:null=True,blank=True
    level_ = {
        (1,"一类号"),
        (2,"二类号"),
        (3,"三类号"),
    }
    statues_ = {
        (1,"占用"),
        (2,"未占用"),
    }
    level = models.SmallIntegerField(verbose_name="级别",choices=level_,default=1)
    status = models.SmallIntegerField(verbose_name="占用情况",choices=statues_,default=2)

迁移数据库命令:

代码语言:javascript
代码运行次数:0
复制
# 生成迁移文件
python manage.py makemigrations

# 应用迁移
python manage.py migrate

可以自己添加点数据并在终端查看是否存入数据库:

代码语言:javascript
代码运行次数:0
复制
 insert into app01_vanitynumber(mobile,price,level,status) values(13992349299,2400,2,2);

与预期无异。

基本功能

大体跟之前用户、部门管理类似,大家也可以玩玩其他的BootStrap样式

路由器

代码语言:javascript
代码运行次数:0
复制
from django.contrib import admin
from django.urls import path
from sqlalchemy.dialects.mssql.information_schema import views
from app01 import views

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", views.vanity_show),
    path("vanity/show/", views.vanity_show),
    path("vanity/add/", views.vanity_add),
    path("vanity/<int:nid>/edit/", views.vanity_edit),
    path("vanity/<int:nid>/delete/", views.vanity_delete),
]

靓号显示

vanity_show.html:

代码语言:javascript
代码运行次数:0
复制
{% extends 'layout.html' %}
{% block content %}
    <div class="panel panel-default" style="margin-left: 40px;margin-right: 40px">
      <div class="panel-heading" style="color: #1265b5">靓号列表</div>
        <a href="/vanity/add/">
            <button type="button" class="btn btn-success" style="margin-top: 10px;margin-left: 10px">
            <span class="glyphicon glyphicon-pencil" aria-hidden="true" ></span>
                添加靓号</button>
        </a>
      <div class="panel-body">
        <div class="bs-example" data-example-id="bordered-table">
        <table class="table table-bordered table-hover table-striped">
          <thead>
            <tr>
              <th>ID</th>
              <th>号码</th>
              <th>价格</th>
              <th>类别</th>
              <th>占用情况</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
          {% for items in queryset %}
            <tr>
              <th scope="row">{
  
  { items.id }}</th>
              <td>{
  
  { items.mobile }}</td>
              <td>{
  
  { items.price }}</td>
              <td>{
  
  { items.get_level_display }}</td>
              <td>{
  
  { items.get_status_display }}</td>
            <td>
                <a class="btn btn-primary btn-xs" href="/vanity/{
  
  { items.id }}/edit/">编辑</a>
                <a class="btn btn-danger btn-xs" href="/vanity/{
  
  { items.id }}/delete/">删除</a>
            </td>
            </tr>
          {% endfor %}
          </tbody>
        </table>
  </div>
      </div>
    </div>

{% endblock %}

靓号添加

vanity_add.html:

代码语言:javascript
代码运行次数:0
复制
{% extends 'layout.html' %}
{% block content %}
    <div class="container-fluid" style="margin-top: 10px">
     <div class="my-div">
        <div class="container">
            <div class="panel panel-default" style="width: 750px;margin-top: 10px">
              <!-- Default panel contents -->
              <div class="panel-heading" style="margin-top: 0">新建 靓号</div>
              <div class="panel-body">
                <form class="form-horizontal" method="POST" action="/vanity/add/">
                    {% csrf_token %}
                  <!-- 输入框 -->
                    {% for items in form %}
                  <div class="form-group">
                    <label class="col-sm-2 control-label">{
  
  { items.label }}</label>
                    <div class="col-sm-5">
{#                      <input type="text" class="form-control" id="inputDepartmentName" placeholder="" name="{
  
  { items.label }}">#}
                        {
  
  { items }}
{#                        要是有错误信息,会显示#}
                        <span style="color: red">{
  
  { items.errors.0 }}</span>
{#                        直接手写{
  
  { items }},因为他会自动帮我们生成html标签#}
                    </div>
                  </div>
{#                        {
  
  { items.label }} : {
  
  { items }}#}
                    {% endfor %}
                  <!-- 提交按钮 -->
                  <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                      <button type="submit" class="btn btn-primary">提 交</button>
                    </div>
                  </div>
                </form>
              </div>
            </div>
        </div>
    </div>
</div>

{% endblock %}

靓号编辑

vanity_edit.html:

代码语言:javascript
代码运行次数:0
复制
{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div class="panel panel-default" style="width: 750px;margin-top: 10px">
              <div class="panel-heading" style="margin-top: 0">编辑 靓号</div>
              <div class="panel-body">
                <form class="form-horizontal" method="POST" >
                    {% csrf_token %}
                  <!-- 输入框 -->
                    {% for items in form %}
                  <div class="form-group">
                    <label for="inputDepartmentName" class="col-sm-2 control-label">{
  
  { items.label }}</label>
                    <div class="col-sm-5">
                        {
  
  { items }}
                        <span style="color: red">{
  
  { items.errors.0 }}</span>
                    </div>
                  </div>
                    {% endfor %}
                  <!-- 提交按钮 -->
                  <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                      <button type="submit" class="btn btn-primary">提 交</button>
                    </div>
                  </div>
                </form>
              </div>
            </div>
    </div>
{% endblock %}

视图函数

代码语言:javascript
代码运行次数:0
复制
from django.shortcuts import render,HttpResponse,redirect
from app01.models import Vanitynumber
from django import forms


class VanitynumberForm(forms.ModelForm):
    class Meta:
        model = Vanitynumber
        fields = ['mobile','price','level','status']

    # 2、循环到所有的插件再赋予form-control样式
    def __init__(self,*args,**kwargs):
        super(VanitynumberForm,self).__init__(*args,**kwargs)
        # 循环找到所有的插件
        for name,field in self.fields.items():
            field.widget.attrs = {'class':'form-control'}
def vanity_show(request):
    form = VanitynumberForm()
    queryset = Vanitynumber.objects.all()
    return render(request,'vanity_show.html',{'form':form,'queryset':queryset})

def vanity_add(request):
    """添加用户,ModelForm版本"""
    if request.method == "GET":
        form = VanitynumberForm()
        return render(request, "vanity_add.html",{"form":form})
    # 用户提交POST请求,校验数据
    form = VanitynumberForm(data=request.POST)
    if form.is_valid():
        form.save()
        return redirect("/vanity/show")
    else:
        print(form.errors)

def vanity_edit(request,nid):
    row_object = Vanitynumber.objects.filter(id=nid).first()
    if request.method == "GET":
        # 根据ID去数据库获取要编辑的那一行数据(对象)
        # 加上instance=row_object会默认将对应ID的数据显示到页面输入框中,这就比之前的部门管理要方便很多
        form = VanitynumberForm(instance=row_object)
        return render(request, "vanity_edit.html", {"form": form})
    # 如果不加下面这行代码,并且UserForm中加instance,那么数据库中就不是更新数据,因为程序不知道要更新哪一行数据,所有程序会自动新添加一行数据,原来数据保持不变
    form = VanitynumberForm(data=request.POST, instance=row_object)
    if form.is_valid():
        form.save()
        return redirect("/vanity/show/")
    return render(request, "vanity_edit.html", {"form": form})

def vanity_delete(request,nid):
    Vanitynumber.objects.filter(id=nid).delete()
    return redirect("/vanity/show/")

额外功能

搜索功能

搜索功能就是按照输入的某些数字,在已有号码中搜索满足某些条件的内容

Django中搜索的两张方式:

都是差不多的,区别在于第二种传字典作为参数

第一种:

代码语言:javascript
代码运行次数:0
复制
q1 = Vanitynumber.objects.filter(status=1,id=1)
print(q1)

第二种:

代码语言:javascript
代码运行次数:0
复制
data_list = {"mobile":"19999234567","id":3}
q2 = Vanitynumber.objects.filter(**data_list)
print(q2)

使用第二种更方便做其他操作,比如加正则。

Django还提供了一些更加便捷的索引规则,比如双下划线,可将具体筛选规则以字典形式传参,前面要加上双星号。

代码语言:javascript
代码运行次数:0
复制
Vanitynumber.objects.filter(id=12)       # 等于12
Vanitynumber.objects.filter(id__gt=12)   # 大于12
Vanitynumber.objects.filter(id__gte=12)  # 大于等于12
Vanitynumber.objects.filter(id__lt=12)   # 小于12
Vanitynumber.objects.filter(id__lte=12)  # 小于等于12

data_dict1 = {"id__lte":12}
Vanitynumber.objects.filter(**data_dict1)

Vanitynumber.objects.filter(mobile="999")               # 等于
Vanitynumber.objects.filter(mobile__startswith="1999")  # 筛选出以1999开头
Vanitynumber.objects.filter(mobile__endswith="222")     # 筛选出以222结尾
Vanitynumber.objects.filter(mobile__contains="222")     # 筛选出包含222

data_dict2 = {"mobile__contains":"222"}
Vanitynumber.objects.filter(**data_dict2)

在展示页面,我们可以在右上方加个输入框和提交按钮,用户接收用户搜索输入语句,有时用户输入可能包含其他字符,我们可以用正则提取到符合条件的内容,这里是连续的数字。通过data_list搜索到的数据,可以返还到html上,显示搜索到的内容。具体实现代码如下:

views.py:

代码语言:javascript
代码运行次数:0
复制
import re
def vanity_show(request):
    form = VanitynumberForm()
    # 先定义一个壳子,再添加
    data_list = {}
    search_data = request.GET.get('q',"")
    search_data = re.search(r'\d+', search_data)
    if search_data:
        search_data=search_data.group()
    else:
        search_data=""
    if search_data:
        data_list["mobile__contains"] = search_data
    queryset = Vanitynumber.objects.filter(**data_list).order_by('-level')
    return render(request,'vanity_show.html',{'form':form,'queryset':queryset,'search_data':search_data})

这里通过GET传参获取q和一个空字符串,作用是使当q无值时,默认为空,以避免因data_list无值而产生报错;对search_data运行正则提取第一个出现的连续数字,如果不为空,则解对象,如果为空,赋值空字符串;再将search_data添加到search_list中;通过filter找到符合条件的queryset,传回html

vanity_show.html:

代码语言:javascript
代码运行次数:0
复制
{% extends 'layout.html' %}
{% block content %}
    <div class="panel panel-default" style="margin-left: 40px;margin-right: 40px">
      <div class="panel-heading" style="color: #1265b5">靓号列表</div>
        <a href="/vanity/add/">
            <button type="button" class="btn btn-success" style="margin-top: 10px;margin-left: 10px">
            <span class="glyphicon glyphicon-pencil" aria-hidden="true" ></span>
                添加靓号</button>
        </a>
        <div style="float: right;width: 300px">
            <div class="input-group" style="display: flex; align-items: center;">
                <form action="" method="GET" style="display: flex; align-items: center;">
                    <label style="margin-top: 11px;margin-right: 4px;margin-bottom: 11px">
                        <input type="text" name="q" class="form-control" placeholder="Search" value="{
  
  { search_data }}" style="margin-right: 4px;">
                    </label>
                    <span class="input-group-btn">
                        <button class="btn btn-primary" type="submit">
                            <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                            <span class="glyphicon-class">搜索</span>
                        </button>
                    </span>
                </form>
            </div>
        </div>
      <div class="panel-body">
        <div class="bs-example" data-example-id="bordered-table">
        <table class="table table-bordered table-hover table-striped">
          <thead>
            <tr>
              <th>ID</th>
              <th>号码</th>
              <th>价格</th>
              <th>类别</th>
              <th>占用情况</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
          {% for items in queryset %}
            <tr>
              <th scope="row">{
  
  { items.id }}</th>
              <td>{
  
  { items.mobile }}</td>
              <td>{
  
  { items.price }}</td>
              <td>{
  
  { items.get_level_display }}</td>
              <td>{
  
  { items.get_status_display }}</td>
            <td>
                <a class="btn btn-primary btn-xs" href="/vanity/{
  
  { items.id }}/edit/">编辑</a>
                <a class="btn btn-danger btn-xs" href="/vanity/{
  
  { items.id }}/delete/">删除</a>
            </td>
            </tr>
          {% endfor %}
          </tbody>
        </table>
  </div>
      </div>
    </div>

{% endblock %}

再将符合条件信息展示到页面上,并将输入框传入search_data作为默认值。

这样,就完成了搜索功能。

分页

一般逻辑

当数据量很大的时候,页面会向下延伸很长,这样不仅影响观感,还浪费空间,可以设置分页功能,为每一页都设置一个最大数据量。

分页的具体逻辑也很简单,也是html标签实现跳转:

代码语言:javascript
代码运行次数:0
复制
<li><a href="/vanity/show/?page={i}"></a></li>

但如果页数很多的话,html文件会很长,而且也不利于一些更复杂的操作,可以在视图函数中以字符串的形式传给html页面,但直接传的话会报错,Django无法正常将字符串标签转换为标签,需要在视图函数中引入mark_safe函数,对字符串进行包裹,类似这样:

代码语言:javascript
代码运行次数:0
复制
mark_safe('<li><a href="/vanity/show/?page={i}"></a></li>')

也可将一个一个的标签,动态存入列表,再使用join函数构造字符串,再用mark_safe包裹,传回html,例如:

代码语言:javascript
代码运行次数:0
复制
data_list = []
for i in range(start_page,end_page+1):
    if i == page:
        str_html_1 = f'<li class="active"><a href="/vanity/show/?page={i}">{i}</a></li>'
    else:
        str_html_1 = f'<li><a href="/vanity/show/?page={i}">{i}</a></li>'
    data_list .append(str_html_1)
data_str = mark_safe("\n".join(data_list ))
queryset = Vanitynumber.objects.filter(**data_list).order_by('-level')[start:end]

对于多行数据,一页是放不下的,可以一页放一定的数据(这里一页放10条),放多页。

此时,对于第一页:页数是1,数据是(0,10)

第二页:页数是2,数据是(10,20)

...............

第 n 页:页数是n,数据是((n-1)×10,n×10)

数据库中的数据条数是可以用函数得到的:

代码语言:javascript
代码运行次数:0
复制
num = Vanitynumber.objects.all().count()

所以可通过总数据条数反推页数

对于特定的某页,可通过索引在数据库中取值:

代码语言:javascript
代码运行次数:0
复制
start = (page-1)*10
end = page * 10
queryset = Vanitynumber.objects.filter(**data_list).order_by('-level')[start:end]

再构造标签字符串,使得页面中点击页码就会跳转到该页,并显示数据。

动态页码

但如果数据量足够多,页码也会很多,在页面中也显示不完,或者说看着很丑,这时,可用动态页码加以改进:

我们希望在页面上展示的页码数不能超过一定的阈值(这里是11)。对于用户提交,从而前端返回的页码数page,我们可用只显示page前五页到page后五页,总共11页

即:

代码语言:javascript
代码运行次数:0
复制
start_page = page - 5
end_page = page + 5

这样去显示效果会好得多,但这样还要问题,当用户点击4页及以前或者最大页码时,左边会出现负数页码,右边则可能会报错,如何解决呢?

可以增加判断语句,如果页码 <= 5,start_page = 1,如果页码 >= 最大页码 - 4,end_page = 最大页码:

代码语言:javascript
代码运行次数:0
复制
if start_page < 1:
    start_page = 1
end_page = page + 5
# 保证页码不会超限
if end_page > int(Vanitynumber.objects.all().count()/10):
    end_page = int(Vanitynumber.objects.all().count()/10)

这样,就能保证不会出现异常。

上下页

增加上下页逻辑很简单,就是点击后page相应地加一减一。需要注意的是“上一页”应当放到最前面,"下一页"放到最后面,因为.append()方法是在后面添加,当然,你也可以使用其他的插入函数。

并且,当page已经是首页或者尾页时,不能跳转了,需要判断一下,具体代码如下:

代码语言:javascript
代码运行次数:0
复制
# 上一页
if page >= 1:
    prev = f'<li><a href="/vanity/show/?page={page-1}">上一页</a></li>'
    page_html_list.append(prev)
else:
    prev = f'<li><a href="/vanity/show/?page=1">上一页</a></li>'
    page_html_list.append(prev)
代码语言:javascript
代码运行次数:0
复制
# 下一页
if page < int(Vanitynumber.objects.all().count() / 10):
    prior = f'<li><a href="/vanity/show/?page={page + 1}">下一页</a></li>'
    page_html_list.append(prior)
else:
    prior = f'<li><a href="/vanity/show/?page={int(Vanitynumber.objects.all().count() / 10)}">下一页</a></li>'
    page_html_list.append(prior)
首尾页

首尾页直接定位即可:

代码语言:javascript
代码运行次数:0
复制
# 首页
page_html_list.append(f'<li><a href="/vanity/show/?page={1}">首页</a></li>')
# 尾页
page_html_list.append(f'<li><a href="/vanity/show/?page={int(Vanitynumber.objects.all().count() / 10)}">尾页</a></li>')

分页相关代码如下:

views.py:

代码语言:javascript
代码运行次数:0
复制
 vanity_show(request):
    form = VanitynumberForm()
    data_list = {}
    search_data = request.GET.get('q',"")
    search_data = re.search(r'\d+', search_data)
    if search_data:
        search_data=search_data.group()
    else:
        search_data=""
    if search_data:
        data_list["mobile__contains"] = search_data

    page = int(request.GET.get('page',1))
    page_html_list = []
    # 如果展示页码大于10
    if int(Vanitynumber.objects.all().count()/10) > 10:
        # 起止页码
        start = (page-1)*10
        end = page*10
        # 页码轮转
        start_page = page - 5
        # 保证页码不会出现非正数
        if start_page < 1:
            start_page = 1
        end_page = page + 5
        # 保证页码不会超限
        if end_page > int(Vanitynumber.objects.all().count()/10):
            end_page = int(Vanitynumber.objects.all().count()/10)
        # 首页
        page_html_list.append(f'<li><a href="/vanity/show/?page={1}">首页</a></li>')
        # 上一页
        if page >= 1:
            prev = f'<li><a href="/vanity/show/?page={page-1}">上一页</a></li>'
            page_html_list.append(prev)
        else:
            prev = f'<li><a href="/vanity/show/?page=1">上一页</a></li>'
            page_html_list.append(prev)

        # 构造标签
        for i in range(start_page,end_page+1):
            if i == page:
                str_html_1 = f'<li class="active"><a href="/vanity/show/?page={i}">{i}</a></li>'
            else:
                str_html_1 = f'<li><a href="/vanity/show/?page={i}">{i}</a></li>'
            page_html_list.append(str_html_1)
        # 下一页
        if page < int(Vanitynumber.objects.all().count() / 10):
            prior = f'<li><a href="/vanity/show/?page={page + 1}">下一页</a></li>'
            page_html_list.append(prior)
        else:
            prior = f'<li><a href="/vanity/show/?page={int(Vanitynumber.objects.all().count() / 10)}">下一页</a></li>'
            page_html_list.append(prior)
        # 尾页
        page_html_list.append(f'<li><a href="/vanity/show/?page={int(Vanitynumber.objects.all().count() / 10)}">尾页</a></li>')
        # mark_safe使得字符串能在页面正常显示
        data_str = mark_safe("\n".join(page_html_list))
        queryset = Vanitynumber.objects.filter(**data_list).order_by('-level')[start:end]
        # 展示页码小于10
    else:
        start = (page - 1) * 10
        end = page * 10
        num = int(Vanitynumber.objects.all().count()/10)
        for i in range(1, num+1):
            if i == page:
                str_html_2 = f'<li class="active"><a href="/vanity/show/?page={i}">{i}</a></li>'
            else:
                str_html_2 = f'<li><a href="/vanity/show/?page={i}">{i}</a></li>'
            page_html_list.append(str_html_2)
        data_str = mark_safe("\n".join(page_html_list))
        queryset = Vanitynumber.objects.filter(**data_list).order_by('-level')[start:end]
    return render(request,'vanity_show.html',{'form':form,'queryset':queryset,'search_data':search_data,'data_str':data_str})

vanity_show:

代码语言:javascript
代码运行次数:0
复制
{% extends 'layout.html' %}
{% block content %}
    <div class="panel panel-default" style="margin-left: 40px;margin-right: 40px">
      <div class="panel-heading" style="color: #1265b5">靓号列表</div>
        <a href="/vanity/add/">
            <button type="button" class="btn btn-success" style="margin-top: 10px;margin-left: 10px">
            <span class="glyphicon glyphicon-pencil" aria-hidden="true" ></span>
                添加靓号</button>
        </a>
        <div style="float: right;width: 300px">
            <div class="input-group" style="display: flex; align-items: center;">
                <form action="" method="GET" style="display: flex; align-items: center;">
                    <label style="margin-top: 11px;margin-right: 4px;margin-bottom: 11px">
                        <input type="text" name="q" class="form-control" placeholder="Search" value="{
  
  { search_data }}" style="margin-right: 4px;">
                    </label>
                    <span class="input-group-btn">
                        <button class="btn btn-primary" type="submit">
                            <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                            <span class="glyphicon-class">搜索</span>
                        </button>
                    </span>
                </form>
            </div>
        </div>
      <div class="panel-body">
        <div class="bs-example" data-example-id="bordered-table">
        <table class="table table-bordered table-hover table-striped">
          <thead>
            <tr>
              <th>ID</th>
              <th>号码</th>
              <th>价格</th>
              <th>类别</th>
              <th>占用情况</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
          {% for items in queryset %}
            <tr>
              <th scope="row">{
  
  { items.id }}</th>
              <td>{
  
  { items.mobile }}</td>
              <td>{
  
  { items.price }}</td>
              <td>{
  
  { items.get_level_display }}</td>
              <td>{
  
  { items.get_status_display }}</td>
            <td>
                <a class="btn btn-primary btn-xs" href="/vanity/{
  
  { items.id }}/edit/">编辑</a>
                <a class="btn btn-danger btn-xs" href="/vanity/{
  
  { items.id }}/delete/">删除</a>
            </td>
            </tr>
          {% endfor %}
          </tbody>
        </table>
  </div>
      </div>
    <ul class="pagination">
        {
  
  { data_str }}
     </ul>
    </div>

{% endblock %}

因为用了ModelForm,无序列表中直接{ { data_str }}即可,无需循环。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据库设置
  • 基本功能
    • 路由器
    • 靓号显示
    • 靓号添加
    • 靓号编辑
    • 视图函数
  • 额外功能
    • 搜索功能
    • 分页
      • 一般逻辑
      • 动态页码
      • 上下页
      • 首尾页
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档