• 博客项目搭建:


    开发一个博客系统。

    博客系统包含两部分:

    • 博客后台,主要用于对 文章、分类、标签 进行管理(类似于博客园后台)。(需登录)

    • 博客主站,用于文章的展示。(无需登录)

    自行设计表结构(至少包含以下字段):

     用户表
      用户名  密码 昵称(博客名称)
     文章表
      标题  文章内容 发表时间  
     分类表
      名称
     标签表
      标签名称

    注:分类和文章是一对多的关系,文章和标签是多对多的关系。关系字段自行设计。

    1. 完成后台系统的登录、注销功能,

      1. 未登录时,右上角显示登录按钮

      2. 登录后,右上角显示用户名,并且可以管理文章、分类、标签。

    2. 完成后台管理(分类、标签、文章)

      1. 表格展示各个表的字段内容

      2. 新增功能

        新增文章时需必须选择一个文章分类,可以选择多个标签

      3. 完成编辑功能

      4. 完成删除功能

        使用一个URL地址和一个视图函数完成

    3. 完成博客主站功能

      1. 博客页:展示出博主的昵称,所有文章标题和简介、时间,点击文章标题跳转至文章页

      2. 文章页:展示文章标题、详细内容、分类、标签

    4. 使用bootstrap的样式

    new project:

     python manage.py startapp backend:

    blogsettings:

    """
    Django settings for blog project.

    Generated by 'django-admin startproject' using Django 1.11.26.

    For more information on this file, see
    https://docs.djangoproject.com/en/1.11/topics/settings/

    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/1.11/ref/settings/
    """

    import os

    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 'iaiz14-lbw$&4l@3vki8u54(-as&d6q1)=h+^uk)q@_jwra8lz'

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True

    ALLOWED_HOSTS = []


    # Application definition

    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'web.apps.WebConfig',
    "backend.apps.BackendConfig", #注册backend.apps.BackendConfig
    ]

    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    ROOT_URLCONF = 'blog.urls'

    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join ( BASE_DIR, 'templates' )]
    ,
    'APP_DIRS': True,
    'OPTIONS': {
    'context_processors': [
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    ],
    },
    },
    ]

    WSGI_APPLICATION = 'blog.wsgi.application'


    # Database
    # https://docs.djangoproject.com/en/1.11/ref/settings/#databases

    #设置默认数据库:
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
    }


    # Password validation
    # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

    AUTH_PASSWORD_VALIDATORS = [
    {
    'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
    ]


    # Internationalization
    # https://docs.djangoproject.com/en/1.11/topics/i18n/

    LANGUAGE_CODE = 'en-us'

    TIME_ZONE = 'UTC'

    USE_I18N = True


    USE_L10N = False #USE_L10N使用

    USE_TZ = True

    DATETIME_FORMAT = "Y-m-d H:i:s"
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/1.11/howto/static-files/

    STATIC_URL = '/static/'

    #定义静态文件路径:
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static")
    ]
    blogurls:
    """blog URL Configuration

    The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
    Examples:
    Function views
    1. Add an import: from my_app import views
    2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
    Class-based views
    1. Add an import: from other_app.views import Home
    2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
    Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
    """
    from django.conf.urls import url,include #include路由分发到不同的urls里面:
    from django.contrib import admin
    #配置不同的urls:
    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^",include("web.urls")),
    url(r"^back/",include("backend.urls")),
    ]
    templatesarticle:
    {% extends  'blog.html' %}

    {% block content %}
    <div class="blog-post">
    <h2 class="blog-post-title">{{ article_obj.title }}</h2>
    <p class="blog-post-meta">{{ article_obj.create_time }}</p>
    {{ article_obj.content|safe }}
    </div>
    {% endblock %}
    weburls:
    from django.conf.urls import url
    from web import views

    urlpatterns = [
    url(r'^login/',views.login,name='login'),
    url(r'^logout/',views.logout,name='logout'),

    url(r"^$",views.blog,name='blog'),
    url(r"^article/(d+)/$",views.article,name='article'),
    ]
    webviews:
    from django.shortcuts import render,redirect
    from web import models

    # Create your views here.

    #定义登录功能:
    def login(request):
    if request.method == "POST":
    #获取用户名和密码:
    name = request.POST.get("login")
    pwd = request.POST.get("pwd")
    #拿到用户名和密码的对象:
    obj = models.User.objects.filter(name=name,pwd=pwd).first()
    #判断对象是否存在:
    if not obj:
    return render(request,"login.html",{"error":"用户名或密码错误"})
    #用户名和密码正确时、保存登录状态、
    request.session["is_login"] = True
    #登录正确后保存用户名:
    request.session["nick"] = obj.nick
    url = request.GET.get("url")
    if url:
    return redirect(url)
    #跳转到文章页:
    return redirect("article_list")
    return render(request,"login.html")

    #定义退出功能:
    def logout(request):
    request.session.flush()
    return redirect("blog")

    #定义博客功能:
    def blog(request):
    user = models.User.objects.all().first()
    all_articles = models.Article.objects.all()
    return render(request,"blog.html",{"user":user,"all_articles":all_articles})

    #定义文章功能:
    def article(request,pk):
    article_obj = models.Article.objects.get(pk=pk)
    return render(request,"article.html",{"article_obj":article_obj})
    backendurls:
    from django.conf.urls import url
    from backend import views

    urlpatterns = [
    url(r"^category_list/",views.category_list,name="category_list"), #定义展示分类路由、反向解析name="category_list"
    url(r"^add_category/",views.add_category,name="add_category"),
    url(r"^edit_category/(d+)/",views.edit_category,name="edit_category"),

    url(r"^tag_list/",views.tag_list,name="tag_list"), #展示标签路由
    url(r"^add_tag/",views.add_tag,name="add_tag"),
    url(r"^edit_tag/(d+)/",views.edit_tag,name="edit_tag"),

    url ( r"^article_list/", views.article_list, name="article_list" ),#展示文章列表
    url ( r"^add_article/", views.add_article, name="add_article" ),
    url ( r"^edit_article/(d+)/", views.edit_article, name="edit_article" ),

    url(r"^delete/(w+)/(d+)/",views.delete,name="del"), #删除功能
    ]
    backendviews:
    from django.shortcuts import render,redirect,reverse
    from web import models
    # Create your views here.
    #定义登录装饰器:
    def login_required(func):
    def inner(request,*args,**kwargs):
    is_login = request.session.get("is_login")
    if not is_login:
    url = request.path_info
    return redirect("{}?url={}".format(reverse('login'),url))
    return func(request,*args,**kwargs)
    return inner

    @login_required
    #定义分类功能category_list:
    def category_list(request):
    #获取所有的分类:
    all_categories = models.Category.objects.all()
    #跳转到分类页面:
    return render(request,"category_list.html",{"all_categories":all_categories})

    @login_required
    #定义增加分类功能add_category:
    def add_category(request):
    if request.method == "POST":
    name = request.POST.get("name")
    models.Category.objects.create(name=name)
    return redirect("category_list")
    return render( request, "category_change.html" )

    @login_required
    #定义编辑分类功能edit_category:
    def edit_category(request,pk):
    #获取要编辑的对象:
    obj = models.Category.objects.filter(pk=pk).first()
    if request.method == "POST":
    name = request.POST.get("name")
    obj.name = name
    obj.save()
    return redirect("category_list")
    return render(request,"category_change.html",{"obj":obj})

    @login_required
    #定义展示标签列表功能tag_list:
    def tag_list(request):
    #获取所有的标签:
    all_tags = models.Tag.objects.all()
    return render(request,"tag_list.html",{"all_tags":all_tags})

    @login_required
    #定义增加标签功能add_tag:
    def add_tag(request):
    if request.method == "POST":
    name = request.POST.get("name")
    models.Tag.objects.create(name=name)
    return redirect("tag_list")
    return render(request,"tag_change.html")

    @login_required
    #定义编辑标签功能edit_tag:
    def edit_tag(request,pk):
    #获取要编辑的标签:
    obj = models.Tag.objects.filter(pk=pk).first()
    if request.method == "POST":
    name = request.POST.get("name")
    obj.name = name
    obj.save()
    return redirect("tag_list")
    return render(request,"tag_change.html",{"obj":obj})

    @login_required
    #定义展示文章功能article_list:
    def article_list(request):
    #获取所有的文章:
    all_articles = models.Article.objects.all()
    return render(request,"article_list.html",{"all_articles":all_articles})

    @login_required
    #定义新增文章功能add_article:
    def add_article(request):
    if request.method == "POST":
    title = request.POST.get("title")
    content = request.POST.get("content")
    category_id = request.POST.get("category_id")
    tag_id = request.POST.getlist("tag_id")
    obj = models.Article.objects.create(title=title,content=content,category_id=category_id,)
    obj.tags.set(tag_id)
    return redirect("article_list")
    all_categories = models.Category.objects.all()
    all_tags = models.Tag.objects.all()
    return render(request,"article_change.html",{"all_categories":all_categories,"all_tags":all_tags})

    @login_required
    #定义编辑文章功能edit_article:
    def edit_article(request,pk):
    obj = models.Article.objects.filter(pk=pk).first()
    if request.method == "POST":
    title = request.POST.get("title")
    content = request.POST.get("content")
    category_id = request.POST.get("category_id")
    tag_id = request.POST.getlist("tag_id")
    obj.tags.set(tag_id)
    models.Article.objects.filter(pk=pk).update(title=title,content=content,category_id=category_id,)
    return redirect("article_list")
    all_categories = models.Category.objects.all()
    all_tags = models.Tag.objects.all()
    return render(request,"article_change.html",{"obj":obj,"all_categories":all_categories,"all_tags":all_tags})

    @login_required
    #定义删除功能delete:
    def delete(request,table,pk):
    #使用反射获取类:
    table_class = getattr(models,table.capitalize())
    table_class.objects.filter(pk=pk).delete()
    return redirect("{}_list".format(table))
    login:
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <title>登录界面</title>
    {% load static %} #静态文件的模板语法:
    <link href="{% static 'css/default.css' %}" rel="stylesheet" type="text/css">

    <link href="{% static 'css/styles.css' %}" rel="stylesheet" type="text/css">
    <link href="{% static 'css/demo.css' %}" rel="stylesheet" type="text/css">
    <link href="{% static 'css/loaders.css' %}" rel="stylesheet" type="text/css">
    <link id="layuicss-skinlayercss" rel="stylesheet"
    href="http://jq22.com/demo/jQueryLogin201708272212/layui/css/modules/layer/default/layer.css?v=3.0.3303"
    media="all">
    </head>
    <body style="">
    <canvas class="pg-canvas" width="1366" height="238"></canvas>
    <div class="login">
    <div class="login_title">
    <span>管理员登录</span>
    </div>
    <div class="login_fields">
    <form action="" method="post">
    {% csrf_token %}
    <div class="login_fields__user">
    <div class="icon">
    <img alt="" src="{% static 'img/user_icon_copy.png' %}">
    </div>
    <input name="login" placeholder="用户名" maxlength="16" type="text" autocomplete="off" value="kbcxy">
    <div class="validation">
    <img alt="" src="{% static 'img/tick.png' %}">
    </div>
    </div>
    <div class="login_fields__password">
    <div class="icon">
    <img alt="" src="{% static 'img/lock_icon_copy.png' %}">
    </div>
    <input name="pwd" placeholder="密码" maxlength="16" type="text" autocomplete="off">
    <div class="validation">
    <img alt="" src="{% static 'img/tick.png' %}">
    </div>
    </div>
    <div class="login_fields__password">
    <div class="icon">
    <img alt="" src="{% static 'img/key.png' %}">
    </div>
    <input name="code" placeholder="验证码" maxlength="4" type="text" autocomplete="off">
    <div class="validation" style="opacity: 1; right: -5px;top: -3px;">
    <canvas class="J_codeimg" id="myCanvas" onclick="Code();">对不起,您的浏览器不支持canvas,请下载最新版浏览器!</canvas>
    </div>
    </div>
    <div class="login_fields__submit">
    <input type="submit" value="登录">
    </div>
    </form>
    </div>
    <div class="success">
    </div>
    <div class="disclaimer">
    <p>欢迎登陆后台管理系统</p>
    </div>
    </div>
    <div class="authent">
    <div class="loader" style="height: 44px; 44px;margin-left: 28px;">
    <div class="loader-inner ball-clip-rotate-multiple">
    <div></div>
    <div></div>
    <div></div>
    </div>
    </div>
    <p>认证中...</p>
    </div>
    <div class="OverWindows"></div>
    <link href="{% static 'css/layui.css' %}" rel="stylesheet" type="text/css">
    <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script>
    <script src="https://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script>
    <script type="text/javascript" src="{% static 'js/jquery-ui.min.js' %}"></script>
    <script type="text/javascript" src="{% static 'js/stopExecutionOnTimeout.js?t=1' %}"></script>
    <script src="{% static 'js/layui.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/Particleground.js' %}" type="text/javascript"></script>
    <script src="{% static 'Js/Treatment.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/jquery.mockjax.js' %}" type="text/javascript"></script>
    <script type="text/javascript">
    var canGetCookie = 0;//是否支持存储Cookie 0 不支持 1 支持
    var ajaxmockjax = 1;//是否启用虚拟Ajax的请求响 0 不启用 1 启用
    //默认账号密码

    var truelogin = "kbcxy";
    var truepwd = "mcwjs";

    var CodeVal = 0;
    Code();

    function Code() {
    if (canGetCookie == 1) {
    createCode("AdminCode");
    var AdminCode = getCookieValue("AdminCode");
    showCheck(AdminCode);
    } else {
    showCheck(createCode(""));
    }
    }

    function showCheck(a) {
    CodeVal = a;
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    ctx.clearRect(0, 0, 1000, 1000);
    ctx.font = "80px 'Hiragino Sans GB'";
    ctx.fillStyle = "#E8DFE8";
    ctx.fillText(a, 0, 100);
    }

    $(document).keypress(function (e) {
    // 回车键事件
    if (e.which == 13) {
    $('input[type="button"]').click();
    }
    });
    //粒子背景特效
    $('body').particleground({
    dotColor: '#E8DFE8',
    lineColor: '#133b88'
    });
    $('input[name="pwd"]').focus(function () {
    $(this).attr('type', 'password');
    });
    $('input[type="text"]').focus(function () {
    $(this).prev().animate({'opacity': '1'}, 200);
    });
    $('input[type="text"],input[type="password"]').blur(function () {
    $(this).prev().animate({'opacity': '.5'}, 200);
    });
    $('input[name="login"],input[name="pwd"]').keyup(function () {
    var Len = $(this).val().length;
    if (!$(this).val() == '' && Len >= 5) {
    $(this).next().animate({
    'opacity': '1',
    'right': '30'
    }, 200);
    } else {
    $(this).next().animate({
    'opacity': '0',
    'right': '20'
    }, 200);
    }
    });
    var open = 0;
    layui.use('layer', function () {
    var msgalert = '默认账号:' + truelogin + '<br/> 默认密码:' + truepwd;
    var index = layer.alert(msgalert, {
    icon: 6,
    time: 4000,
    offset: 't',
    closeBtn: 0,
    title: '友情提示',
    btn: [],
    anim: 2,
    shade: 0
    });
    layer.style(index, {
    color: '#777'
    });
    //非空验证
    $('input[type="button"]').click(function () {
    var login = $('input[name="login"]').val();
    var pwd = $('input[name="pwd"]').val();
    var code = $('input[name="code"]').val();
    if (login == '') {
    ErroAlert('请输入您的账号');
    } else if (pwd == '') {
    ErroAlert('请输入密码');
    } else if (code == '' || code.length != 4) {
    ErroAlert('输入验证码');
    } else {
    //认证中..
    fullscreen();
    $('.login').addClass('test'); //倾斜特效
    setTimeout(function () {
    $('.login').addClass('testtwo'); //平移特效
    }, 300);
    setTimeout(function () {
    $('.authent').show().animate({right: -320}, {
    easing: 'easeOutQuint',
    duration: 600,
    queue: false
    });
    $('.authent').animate({opacity: 1}, {
    duration: 200,
    queue: false
    }).addClass('visible');
    }, 500);

    //登陆
    var JsonData = {login: login, pwd: pwd, code: code};
    //此处做为ajax内部判断
    var url = "";
    if (JsonData.login == truelogin && JsonData.pwd == truepwd && JsonData.code.toUpperCase() == CodeVal.toUpperCase()) {
    url = "Ajax/Login";
    } else {
    url = "Ajax/LoginFalse";
    }


    AjaxPost(url, JsonData,
    function () {
    //ajax加载中
    },
    function (data) {
    //ajax返回
    //认证完成
    setTimeout(function () {
    $('.authent').show().animate({right: 90}, {
    easing: 'easeOutQuint',
    duration: 600,
    queue: false
    });
    $('.authent').animate({opacity: 0}, {
    duration: 200,
    queue: false
    }).addClass('visible');
    $('.login').removeClass('testtwo'); //平移特效
    }, 2000);
    setTimeout(function () {
    $('.authent').hide();
    $('.login').removeClass('test');
    if (data.Status == 'ok') {
    //登录成功
    $('.login div').fadeOut(100);
    $('.success').fadeIn(1000);
    $('.success').html(data.Text);
    //跳转操作

    } else {
    AjaxErro(data);
    }
    }, 2400);
    })
    }
    })
    })
    var fullscreen = function () {
    elem = document.body;
    if (elem.webkitRequestFullScreen) {
    elem.webkitRequestFullScreen();
    } else if (elem.mozRequestFullScreen) {
    elem.mozRequestFullScreen();
    } else if (elem.requestFullScreen) {
    elem.requestFullscreen();
    } else {
    //浏览器不支持全屏API或已被禁用
    }
    }
    if (ajaxmockjax == 1) {
    $.mockjax({
    url: 'Ajax/Login',
    status: 200,
    responseTime: 50,
    responseText: {"Status": "ok", "Text": "登陆成功<br /><br />欢迎回来"}
    });
    $.mockjax({
    url: 'Ajax/LoginFalse',
    status: 200,
    responseTime: 50,
    responseText: {"Status": "Erro", "Erro": "账号名或密码或验证码有误"}
    });
    }
    </script>


    <div class="layui-layer-move"></div>
    </body>
    </html>
    pycharm编辑器页面:
    网站页面展示效果:

    webmodels:
    from django.db import models

    # Create your models here.

    #定义用户表:用户名、密码、昵称(博客名称)
    class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    nick = models.CharField(max_length=32)

    #定义文章表:标题、文章内容、发表时间
    class Article(models.Model):
    title = models.CharField(max_length=32)
    content = models.TextField() #TextField是文本长整型
    create_time = models.DateTimeField(auto_now_add=True) #DateTimeField是日期时间字段、auto_now_add=True意思是只有新增时才会增加
    #定义分类和文章是一对多的关系、分类是一、文章是多、外键是分类的字符串字段形式、定义在文章表里面:
    category = models.ForeignKey("Category",on_delete=models.SET_NULL,null=True)
    #定义文章和标签是多对多的关系用ManyToManyField
    tags = models.ManyToManyField("Tag")

    #定义分类表:名称
    class Category(models.Model):
    name = models.CharField(max_length=32)

    #定义标签表:标签名称
    class Tag(models.Model):
    name = models.CharField(max_length=32)
    数据库迁移命令:

    python manage.py makemigrations

    python manage.py migrate

  • 相关阅读:
    利用arcserver 自带tomcat实现上传shapefile、cad等文件,然后用soe解析。
    Linux下ls命令显示符号链接权限为777的探索
    HTTP严格安全传输(HTTP Strict Transport Security, HSTS)chromuim实现源码分析(一)
    利用Python sklearn的SVM对AT&T人脸数据进行人脸识别
    使用sklearn构建含有标量属性的决策树
    SEED缓冲区溢出实验笔记——Return_to_libc
    Python写的嗅探器——Pyside,Scapy
    PySide——Python图形化界面入门教程(六)
    PySide——Python图形化界面入门教程(五)
    PySide——Python图形化界面入门教程(四)
  • 原文地址:https://www.cnblogs.com/zhang-da/p/12088169.html
Copyright © 2020-2023  润新知