Django实战(一)——教育网站 - Go语言中文社区

Django实战(一)——教育网站


WEB开发流程

一、需求分析

二、数据库设计

三、后台管理系统

四、全栈功能实现

五、基础功能补充

六、xadmin的进阶开发

 

django目录

一级目录:

项目:MxOnline

MxOnline:配置文件

apps:后台业务数据库,路由,view

extra_app:从系统外部导入的app

log:保存系统的日志文件

static:存放前端的静态文件:css、js、img、images

templates:存放前端的网页:html

media:存放用户上传下载的文件

 

二、数据库设计——Django app 设计

1.环境搭建

2.user-用户管理

3.course-课程管理

4.orgnization-机构和教师管理

5.operation-用户操作管理

6.app搜索路径的设置

 

1.环境搭建

1.1 虚拟环境搭建

用到的包是virtualenv和vrtualenvwrapper-win

新建虚拟环境

mkvirtualenv mxonline

激活虚拟环境

workon mxonline

1.2 新建项目

django-admin startproject MxOnline

python manage.py startapp user


1.3 安装包

pip install django==1.9

pip install mysqlclient #连接数据库

pip install pillow #图片的加载

1.4 配置数据库

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "mxonline",
        'USER': "root",
        'PASSWORD': "888888",
        'HOST':  "127.0.0.1",
    }
}

数据迁移

python manage.py makemigrations

python manage.py migrate

1.5配置 templates

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,

1.6 配置 static

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

2.user-用户管理

在user.model中设置三个class实现不同的功能

2.1 UserProfile

继承原有表user中的字段,新填个性化字段

AUTH_USER_MODEL = "user.UserProfile"

 

# _*_ encoding:utf-8 _*_
from django.db import models

from django.contrib.auth.models import AbstractUser #继承原有表user中的字段,新填个性化字段
# Create your models here.

class UserProfile(AbstractUser):
    nick_name = models.CharField(max_length=50, verbose_name=u"昵称", default=u"")
    birthday = models.DateField(verbose_name=u"生日", null=True, blank=True)
    gender = models.CharField(max_length=5, choices=(("male", u"男"), ("female", "女")), default=u"")
    address = models.CharField(max_length=100, default=u"")
    mobile = models.CharField(max_length=11, null=True, blank=True)
    image = models.ImageField(upload_to="image/%y/%m", default=u"image/default.png", max_length=100)

    class Meta:
        verbose_name = "用户信息"
        verbose_name_plural = verbose_name

    def __unicode__(self):
        return self.username

 容易出现的错误,循环引用出错,必须分层,解决方案,分层 operation表示用户行为

2.2 EmailVerifyRecord 邮箱验证码

class EmailVerifiyRecord(models.Model):
    code = models.CharField(max_length=20, verbose_name=u"验证码")
    email = models.EmailField(max_length=50, verbose_name=u"邮箱")
    send_type = models.CharField(choices=(("regiser", u"注册"), ("forget", u"找回密码")), max_length=10)
    send_time = models.DateField(default=datetime.now)

    class Meta:
        verbose_name = u"邮箱验证码"
        verbose_name_plural = verbose_name

2.3 Banner 轮播图

class Banner(models.Model):
    title = models.CharField(max_length=100, verbose_name=u"标题")
    image = models.ImageField(upload_to="banner/%Y/%m", verbose_name=u"轮播图", max_length=100)
    url = models.URLField(max_length=200, verbose_name=u"访问地址")
    index = models.IntegerField(default=100, verbose_name=u"顺序")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        verbose_name = u"轮播图"
        verbose_name_plural = verbose_name

3.course-课程管理

3.1 Course 课程基本信息

class Course(models.Model):
    name = models.CharField(max_length=50, verbose_name=u"课程名")
    desc = models.CharField(max_length=300, verbose_name=u"课程描述")
    detail = models.TextField(verbose_name=u"课程详情")
    degree = models.CharField(choices=(("cj", "初级"), ("zj", "中级"), ("gj", "高级")), max_length=2)
    learn_time = models.IntegerField(default=0, verbose_name=u"学习时长(分钟)")
    student = models.IntegerField(default=0, verbose_name=u"学习人数")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏人数")
    image = models.ImageField(upload_to="course/%Y/m", verbose_name=u"封面图", max_length=100)
    click_nums = models.IntegerField(default=0, verbose_name=u"点击数")
    add_time = models.DateField(default=datetime.now,verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"课程"
            verbose_name_plural = verbose_name

3.2 Lesson 章节信息

class Lesson(models.Model):
    course = models.ForeignKey(Course, verbose_name=u"课程")
    name = models.CharField(max_length=100, verbose_name=u"章节名")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"章节"
            verbose_name_plural = verbose_name

3.3 Video 视频信息

class Video(models.Model):
    lesson = models.ForeignKey(Lesson, verbose_name=u"章节")
    name = models.CharField(max_length=100, verbose_name=u"视频名")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"视频"
            verbose_name_plural = verbose_name

3.4 课程资源

class CourseResource(models.Model):
    course = models.ForeignKey(Course, verbose_name=u"课程")
    name = models.CharField(max_length=100, verbose_name=u"名称")
    download = models.FileField(upload_to="course/%Y/%m", verbose_name=u"资源文件", max_length=100)
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"课程资源"
            verbose_name_plural = verbose_name

4.orgnization-机构和教师管理

 

4.1 CourseOrg 课程机构基本信息

class CourseOrg(models.Model):
    name = models.CharField(max_length=50, verbose_name=u"机构名称")
    desc = models.TextField(verbose_name=u"机构描述")
    click_nums = models.IntegerField(default=0, verbose_name=u"点击数")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏数")
    image = models.ImageField(upload_to="org/%Y/m", verbose_name=u"封面图", max_length=100)
    address = models.CharField(max_length=150, verbose_name=u"机构地址")
    city = models.ForeignKey(CityDict, verbose_name=u"所咋城市")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"课程机构"
            verbose_name_plural = verbose_name

4.2教师信息

class Teacher(models.Model):
    org = models.ForeignKey(CourseOrg, verbose_name=u"所属机构")
    name = models.CharField(max_length=50, verbose_name=u"教师名")
    work_years = models.IntegerField(default=0, verbose_name=u"工作年限")
    work_company = models.CharField(max_length=50, verbose_name=u"就职公司")
    work_position = models.CharField(max_length=50, verbose_name=u"公司职位")
    points = models.CharField(max_length=50, verbose_name=u"教学特点")
    click_nums = models.IntegerField(default=0, verbose_name=u"点击数")
    fav_nums = models.IntegerField(default=0, verbose_name=u"收藏数")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"教师"
            verbose_name_plural = verbose_name

4.3 城市信息

class CityDict(models.Model):
    name = models.CharField(max_length=20, verbose_name=u"城市")
    desc = models.CharField(max_length=200, verbose_name=u"描述")
    add_time = models.DateField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        class Meta:
            verbose_name = u"城市"
            verbose_name_plural = verbose_name

 

5.operation-用户操作管理

5.1  UserAsk 用户咨询

class UserAsk(models.Model):
    name = models.CharField(max_length=20, verbose_name=u"姓名")
    mobile = models.CharField(max_length=11, verbose_name=u"手机")
    course_name = models.CharField(max_length=20, verbose_name=u"课程名")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
            verbose_name = u"用户咨询"
            verbose_name_plural = verbose_name

5.2 CourseComments 用户评论

class CourseComments(models.Model):
    #课程评论
    user = models.ForeignKey(UserProfile,verbose_name=u"用户")
    course = models.ForeignKey(Course,verbose_name=u"课程")
    comments = models.CharField(max_length=200, verbose_name=u"评论")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        verbose_name = u"课程评论"
        verbose_name_plural = verbose_name

5.3 UserFavorite 用户收藏

class UserFavorite(models.Model):
    user = models.ForeignKey(UserProfile, verbose_name=u"用户")
    fav_id = models.IntegerField(default=0, verbose_name=u"数据id")
    fav_type = models.IntegerField(choices=((1, "课程"), (2,"课程机构"), (3,"讲师")), default=1, verbose_name=u"收藏类型")

    class Meta:
        verbose_name = u"用户收藏"
        verbose_name_plural = verbose_name

5.4 UserMessage 用户消息

class UserMessage(models.Model):
    user = models.IntegerField(default=0, verbose_name=u"接受用户")
    message = models.CharField(max_length=500, verbose_name=u"消息内容")
    has_read = models.BooleanField(default=False, verbose_name=u"是否已读")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        verbose_name = u"用户消息"
        verbose_name_plural = verbose_name

5.5UserCourse 用户学习的课程

class UserCourse(models.Model):
    user = models.ForeignKey(UserProfile, verbose_name=u"用户")
    course = models.ForeignKey(Course, verbose_name=u"课程")
    add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加时间")

    class Meta:
        verbose_name = u"用户课程"
        verbose_name_plural = verbose_name

6.app搜索目录的配置

统一将app放在一个文件夹下便于管理,需要在settings中设置

import os
import sys

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

三、后台管理系统——django admin

1.权限管理;2.xadmin;3.用户登陆和注册

 

1.权限管理

创建超级用户

python manage.py createsuperuser

#root
#root280010

将后台设置成中文名

LANGUAGE_CODE = 'zh-hans' #中文

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False #本地时间

在管理台上注册用户信息

在admin.py下注册


from .models import UserProfile

class UserProfileAdmin(admin.ModelAdmin):
    pass

admin.site.register(UserProfile, UserProfileAdmin)

注意:添加用户注意在settings里取消外键约束

'OPTIONS': {
            "init_command": "SET foreign_key_checks = 0;",

2.xadmin【难点+重点】

2.1 xadmin的安装

因为python3.6不支持xadmin的直接安装,所以直接从GitHub获取https://github.com/sshwsfc/xadmin 

1)新建空白文件README.rst 压缩进 zip 中替换掉同名文件

下载后,从错误中可以看到,是文件README.rst 出现了 Unicode 解码错误,这个文件时没有什么用处的,可以新建一个同名的空白文件替换掉。

(2). 然后我们通过 cd 命令切换到该文件夹目录下,通过下面命令安装:

python setup.py install

(3)安装完成后,通过 pip list 可以看到 xadmin 以及相关依赖包都安装完成了。

(4)安装 import_export的包 

但是你实际运行的时候又会发现,所以继续 安装成功以后,xadmin就算安装成功了。

pip install django-import-export

2.2 xadmin 配置

(1)在settings文件下

INSTALLED_APPS = (
    
    'xadmin',
    'crispy_forms',
    'reversion',
   
)

(2)在url文件下

import xadmin
    # url(r'^admin/', admin.site.urls),
    url(r'^xadmin/', xadmin.site.urls),

2.3更新数据迁移

数据库会更新出一些新的表

2.4 源码的安装

也可以将xadmin拷贝到项目中,修改源码,提供丰富的插件

 

在settings中设置

import os
import sys

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))

至此xadmin安装成功 ,截图如下(不容易)

xadmin后台管理的特点是:基于BootStrap3,内置功能丰富,强大的插件系统

2.5 注册models

新建adminx.py

# _*_ coding: utf-8 _*_

import xadmin

from .models import CityDict, CourseOrg, Teacher


class CityDictAdmin(object):
    list_display = ['name', 'desc', 'add_time']  #显示列
    search_fields = ['name', 'desc']             #搜索
    list_filter = ['name', 'desc', 'add_time']   #过滤器


class CourseOrgAdmin(object):
    list_display = [' name', 'desc', 'click_nums', 'fav_nums', 'image', 'address', 'city', 'add_time']  # 显示列
    search_fields = [' name', 'desc', 'click_nums', 'fav_nums', 'image', 'address', 'city']             # 搜索
    list_filter = [' name', 'desc', 'click_nums', 'fav_nums', 'image', 'address', 'city', 'add_time']   # 过滤器


class TeacherAdmin(object):
    list_display = ['org', 'name', 'work_years', 'work_company', 'work_position', 'points', 'click_nums', 'fav_nums', 'add_time']   # 显示列
    search_fields = ['org', 'name', 'work_years', 'work_company', 'work_position', 'points', 'click_nums', 'fav_nums']              # 搜索
    list_filter = ['org', 'name', 'work_years', 'work_company', 'work_position', 'points', 'click_nums', 'fav_nums', 'add_time']    # 过滤器



xadmin.site.register(CityDict, CityDictAdmin)
xadmin.site.register(CourseOrg, CourseOrgAdmin)
xadmin.site.register(Teacher, TeacherAdmin)

2.6 xadmin页面的主题修改

(1)显示主题修改页面风格

from xadmin import views

class BaseSetting(object):
    enable_themes = True
    use_bootswatch = True

class GlobalSettings(object):
    site_title = "鹏鹏教学后台管理系统"
    site_footer = "鹏鹏教学网"

xadmin.site.register(views.BaseAdminView, BaseSetting)
xadmin.site.register(views.CommAdminView, GlobalSettings)

(2)导航栏的设置以及更改apps为中文名

apps.py设置

# _*_ coding: utf-8 _*_
from django.apps import AppConfig

class OperationConfig(AppConfig):
    name = 'operation'
    verbose_name = u"用户操作"

__init__.py设置

default_app_config = "user.apps.UserConfig"

效果图

四、全栈功能实现

    1.用户的登陆和注册,密码找回

    2.课程管理模块——授课机构

    3.课程列表页面——公开课

    4.教师管理模块——授课教师

 

 1.用户的登陆和注册,密码找回

跳转页面login前没有/,将css,js,images导入到static,并配置static

from user.views import LoginView

urlpatterns = [
    url(r'^xadmin/', xadmin.site.urls),

    url('^$', TemplateView.as_view(template_name="index.html"), name="index"),
    url('^login/$', LoginView.as_view(), name="login"),
]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
    ("css", os.path.join(STATIC_ROOT, 'css')),
    ("images", os.path.join(STATIC_ROOT, 'images').replace('\', '/')),
    ("js", os.path.join(STATIC_ROOT, 'js')),
    ("img", os.path.join(STATIC_ROOT, 'img')),

1.1登陆后台编写

(0)url.py编写

from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateView
import xadmin
from user.views import LoginView

urlpatterns = [
    url(r'^xadmin/', xadmin.site.urls),

    url('^$', TemplateView.as_view(template_name="index.html"), name="index"),
    url('^login/$', LoginView.as_view(), name="login"),
]

(1)views.py

from django.contrib.auth import authenticate, login
from django.views.generic.base import View
#用户登陆模块
class LoginView(View):
    def get(self, request):
        return render(request, "login.html", {})
    def post(self, request):
        #提交到表单form里面做验证
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            user_name = request.POST.get("username", "")
            pass_word = request.POST.get("password", "")
            user = authenticate(username=user_name, password=pass_word)
            if user is not None:
                login(request, user)
                return render(request, "index.html")
            else:
                return render(request, "login.html", {"msg": "用户名或密码错误!"})
        else:
            return render(request, "login.html", {"login_form": login_form})

(2)设置email和username同时可以登陆

settings.py配置

# Application definition
AUTHENTICATION_BACKENDS = (
    'user.views.CustomBackend',
)
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q  #并集

from .models import UserProfile

#使用邮箱也可以登陆
class CustomBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
        try:
            user = UserProfile.objects.get(Q(username=username) | Q(email=username))  #完成自定义登陆
            if user.check_password(password):
                return user
        except Exception as e:
            return None

(3)html设置

index.html设置

 {% if request.user.is_authenticated %}
                <div class="top">
                    <div class="wp">
					<div class="fl"><p>服务电话:<b>18582854749</b></p></div>
					<!--登录后跳转-->
						<div class="personal">
                            <dl class="user fr">
                                <dd>鹏鹏<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                            	<dl>
	                                <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
	                                <dd>
	                                    <h2>管理员</h2>
	                                    <p>root@qq.com</p>
	                                </dd>
                                </dl>
                                <div class="btn">
	                                <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
	                                <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>


				</div>
			</div>

                    {% else %}
                    <div class="top">
                        <a style="color:white" class="fr registerbtn" href="register.html">注册</a>
                        <a style="color:white" class="fr loginbtn" href="/login/">登录</a>

            {% endif %}

login.html  如果用户信息出错,则显示错误信息

<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>

(4)form表单

用于验证用户名和密码,减轻后台验证的负担

后台新建form.py

#表单,用来验证
from django import forms


class LoginForm(forms.Form):
    username = forms.CharField(required=True)
    password = forms.CharField(required=True, min_length=5)

前端设置信息

#高亮
 <div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">

#错误提示
 <div class="error btns login-form-tips" id="jsLoginTips">{% for key, error in login_form.errors.items %}{{ key }}:{{ error }}{% endfor %}{{ msg }}</div>

#路径返回
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">

{% csrf_token %}

#信息回填
value="{{ register_form.email.value }}

效果图如下:

 (5)cookies和sesson机制实现自动登陆

cookie在本地浏览器,sesson服务器

 

 1.2 注册后台编写

(1)配置

url.py

url('^register/$', RegisterView.as_view(), name="register"),

index.html

 <div class="top">
                        <a style="color:white" class="fr registerbtn" href="{% url 'register' %}">注册</a>
                        <a style="color:white" class="fr loginbtn" href="{% url 'login' %}">登录</a>

register.html,使用这样的方式设置路径,便于以后路径的修改

<!DOCTYPE html>
<html>
{% load staticfiles %}

link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">

图片验证码的配置

 #1.pip
 pip install  django-simple-captcha==0.4.6

2.Add captcha to the INSTALLED_APPS in your settings.py


3.Add an entry to your urls.py:

urlpatterns += [
    url(r'^captcha/', include('captcha.urls')),
]
#生成数据库表
python manage.py makemigrations
python manage.py migrate

逻辑设计,view.py

#用户注册
class RegisterView(View):
    def get(self, request):
        register_form = RegisterForm()
        return render(request, "register.html", {'register_form': register_form})

    def post(self, request):
        register_form = RegisterForm(request.POST)
        if register_form.is_valid():
            user_name = request.POST.get("email", "")
            pass_word = request.POST.get("password", "")
            #实例化
            user_profile = UserProfile()
            user_profile.username = user_name
            user_profile.email = user_name
            #用户激活
            user_profile.is_active = False
            #对铭文加密
            user_profile.password = make_password(pass_word)
            user_profile.save()

            send_register_email(user_name, "register")
            return render(request, "login.html")
        else:
            return render(request, "register.html", {"register_form": register_form})

 用户激活的配置

url

 url(r'^active/(?P<active_code>.*)/$', ActiveUserView.as_view(), name="user_active"),

 settings,注意授权,密码是授权码

#配置邮箱验证
EMAIL_HOST = "smtp.163.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "wenpeng_111@163.com"
EMAIL_HOST_PASSWORD = "51dk648171lm" #授权码
EMAIL_USE_TLS = False
EMAIL_FROM = "wenpeng_111@163.com" #指明发件人

在app里新建utils文件,建立email_send.py

自动生成随机字符串

# _*_ coding: utf-8 _*_
from random import Random
from django.core.mail import send_mail

from user.models import EmailVerifiyRecord
from MxOnline.settings import EMAIL_FROM


def random_str(randomlength=8):
    str = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        str += chars[random.randint(0, length)]
    return str


def send_register_email(email, send_type="register"):
    email_record = EmailVerifiyRecord()
    code = random_str(16)
    email_record.code = code
    email_record.email = email
    email_record.send_type = send_type
    email_record.save()

    email_title = ""
    email_body = ""

    if send_type == "register":
        email_title = "鹏鹏在线网注册激活链接"
        email_body = "请点击下面的链接激活你的账号:http://127.0.0.1:8000/active/{0}".format(code)

        send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
        if send_status:
            pass

1.3找回密码

view.py

#密码找回
class ForgetPwdView(View):
    def get(self, request):
        forget_form = ForgetForm(request.POST)
        return render(request, "forgetpwd.html", {"forget_form": forget_form})
    def post(self, request):
        forget_form = ForgetForm(request.POST)
        if forget_form.is_valid():
            email = request.POST.get("email", "")
            send_register_email(email, "forget")
            return render(request, "send_success.html")
        else:
            return render(request, "forgetpwd.html", {"forget_form": forget_form})


#用户密码激活
class ResetView(View):
    def get(self, request, active_code):
        all_records = EmailVerifiyRecord.objects.filter(code=active_code)
        if all_records:
            for record in all_records:
                email = record.email
                return render(request, "password_reset.html", {"email": email})
        else:
            return render(request, "active_fail.html")
        return render(request, "login.html")
#密码提交
class ModifyPwdView(View):
    def post(self, request):
        #把请求放进表单进行验证
        modify_form = ModifyPwdForm(request.POST)
        if modify_form.is_valid():
            #获取页面数据
            pwd1 = request.POST.get("password1", "")
            pwd2 = request.POST.get("password2", "")
            #取出要修改的用户
            email = request.POST.get("email", "")
            if pwd1 != pwd2:
                return render(request, "password_reset.html", {"email": email, "msg": "密码不一致,请重新输入"})
            user = UserProfile.objects.get(email=email)
            user.password = make_password(pwd1)
            user.save()
            return render(request, "login.html")
        else:
            email = request.POST.get("email", "")
            return render(request, "password_reset.html", {"email": email, "modify_form": modify_form})

 url.py

#密码找回
    url(r'^forget/$', ForgetPwdView.as_view(), name="forget_pwd"),
    url(r'^reset/(?P<active_code>.*)/$', ResetView.as_view(), name="reset_pwd"),
    url(r'^modify_pwd/$', ModifyPwdView.as_view(), name="modify_pwd"),

password_reset.html

<div class="wp">
    <div class="resetpassword" id="resetPwdForm">
        <h1>修改密码</h1>
        <p>已经通过验证,请设置新密码</p>
        <form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
            <ul>
                <li>
                    <span class="">新 密 码 :</span>
                    <input type="password" name="password1" id="pwd" placeholder="6-20位非中文字符">
                    <i></i>
                </li>
                <input type="hidden" name="email" value="{{ email }}">
                <li>
                    <span class="">确定密码:</span>
                    <input type="password" name="password2" id="repwd" placeholder="6-20位非中文字符">
                    <i></i>
                </li>
                <li class="button">
                    <input type="button" value="提交" οnclick="reset_password_form_submit()">
                </li>
            </ul>
            {% csrf_token %}

 

2.课程管理模块——授课机构

templates的继承,注意templates的继承用法,子类替换父类的结构进行扩充。

{% extends 'base.html' %}
{% block title %}课程机构列表 - 慕学在线网{% endblock %}
{% load staticfiles %}
{% block custom_bread %}
    <section>
        <div class="wp">
            <ul  class="crumbs">
                <li><a href="index.html">首页1</a>></li>
                <li>课程机构1</li>
            </ul>
        </div>
    </section>
{% endblock %}

2.1 media的配置

media用于存放用户上传的文件或者图片

 (1)settings.py路径设置

设置 media 路径与目录

import os
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

 settings 中配置模板的处理器

 Templates[
'django.core.context_processors.media',
]

到这一步,仍然不能显示图片,在网页源代码中可以看到有图片的地址。但是仍然需要在 urls 中配置图片地址的路由,让 Django 知道到那个地方去取回图片。

(2)templates中图片地址

data-url="{{ MEDIA_URL }}{{ course_org.image }}

{% for course_org in all_orgs %}

<dl class="des difdes">
 <a href="org-detail-homepage.html">
<img width="200" height="120" class="scrollLoading" 
data-url="{{ MEDIA_URL }}{{ course_org.image }}"/>
            
{% endfor %}
(3)url.py配置一个处理静态文件的路由
# -*- coding:utf-8 -*-
from django.views.static import serve 
from MxOnline.settings import MEDIA_ROOT
 urlpatterns = [ 
# 处理 media 信息,用于图片获取 
url(r'^media/(?P<path>.*)$', serve, {"document_root":MEDIA_ROOT}),]

2.2 分页功能

pip install django-pure-pagination

(1)settings.py

INSTALLED_APPS = (
  'pure_pagination',
)

(2)控制页数设定

PAGINATION_SETTINGS = {
    'PAGE_RANGE_DISPLAYED': 10,
    'MARGIN_PAGES_DISPLAYED': 2,

    'SHOW_FIRST_PAGE_WHEN_INVALID': True,
}

http://i.imgur.com/LCqrt.gif

(3)view.py设定

# _*_ encoding:utf-8 _*_
from django.shortcuts import render
from django.views.generic import View
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger #分页
from .models import CourseOrg, CityDict,Teacher

class OrgView(View):
    #课程机构列表功能
    def get(self, request):
        #课程机构
        all_orgs = CourseOrg.objects.all()
        org_nums = all_orgs.count()
        #城市
        all_cities = CityDict.objects.all()
        #对课程机构进行分页
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        p = Paginator(all_orgs, 4, request=request)
        orgs = p.page(page)
        
        return render(request, "org-list.html", {
            "all_orgs": orgs,
            "all_cities": all_cities,
            "org_nums": org_nums,
            "city_id": city_id,
            "category": category,
            "hot_orgs": hot_orgs,
            "sort": sort
        })

(4)templates设定org-list.html(分页的设定属于约定俗成的东西)

<div class="pageturn">
            <ul class="pagelist">
                {% if all_orgs.has_previous %}
                    <li class="long"><a href="?{{ all_orgs.previous_page_number.querystring }}">前一页</a></li>
                {% endif %}

                {% for page in all_orgs.pages %}
                    {% if page %}
                        {% ifequal page all_orgs.number %}
                            <li class="active"><a href="?{{ page.querystring }}">{{ page }}</a></li>
                        {% else %}
                            <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
                        {% endifequal %}
                    {% else %}
                        <li class="none"><a href="">...</a></li>
                    {% endif %}
                {% endfor %}

                {% if all_orgs.has_next %}
                    <li class="long"><a href="?{{ all_orgs.next_page_number.querystring }}" >下一页</a></li>
                {% endif %}

            </ul>
		    </div>

2.3 列表筛选功能

(1)所属地区筛选

(2)机构类别筛选

view.py

 #取出筛选城市
city_id = request.GET.get('city', "")
if city_id:
    all_orgs = all_orgs.filter(city_id=int(city_id))
#机构类别筛选
category = request.GET.get('ct', '')
if category:
    all_orgs = all_orgs.filter(category=category)
#每一列的总数
org_nums = all_orgs.count()

org-list.html

注意:templates的用法,机构类别的筛选和所在地区的筛选杂糅到一块,直接相互关联!

<h2>机构类别</h2>
<div class="cont">
<a href="?city={{ city_id }}"><span class="{% ifequal category '' %}active2{% endifequal %}">全部</span></a>

<a href="?ct=pxjg&city={{ city_id }}"><span class="{% ifequal category 'pxjg' %}active2{% endifequal %}">培训机构</span></a>

<a href="?ct=gx&city={{ city_id }}"><span class="{% ifequal category 'gx' %}active2{% endifequal %}">高校</span></a>

<a href="?ct=gr&city={{ city_id }}"><span class="{% ifequal category 'gr' %}active2{% endifequal %}">个人</span></a>
</div>

<h2>所在地区</h2>
<div class="more">更多</div>
<div class="cont">

<a href="?ct={{ category }}"><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>

{% for city in all_cities %}
<a href="?city={{ city.id }}&ct={{ category }}"><span class="{% ifequal city_id city.id|stringformat:'i' %}active2{% endifequal %}">{{ city.name }}</span></a>
{% endfor %}
</div>

2.4 列表排序功能

(1)授课机构排名

(2)所属列表排序(学习人数和课程数)

views.py

#课程机构排名
hot_orgs = all_orgs.order_by("click_nums")[:5]
#所属列表排序
sort = request.GET.get('sort', "")
if sort:
    if sort == "students":
        all_orgs = all_orgs.order_by("-students")
    elif sort == "courses":
        all_orgs = all_orgs.order_by("-course_nums")

org-list.html 各种情况下的排序杂糅到一块,一定相互关联!active高亮

#授课机构排序
<div class="right companyrank layout">
<div class="head">授课机构排名</div>

{% for current_org in hot_orgs %}
<dl class="des">
<dt class="num fl">{{ forloop.counter }}</dt>
<dd>
<a href="/company/2/"><h1>{{ current_org.name }}</h1></a>
<p>{{ current_org.address }}</p>
</dd>
</dl>
{% endfor %}
</div>

#所属列的排序
<div class="head">
    <ul class="tab_header">
        <li class="{% if sort == '' %}active{% endif %}"><a href="?&ct{{ category }}&city{{ city_id }}">全部</a> </li>
        <li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students&ct{{ category }}&city{{ city_id }}">学习人数 &#8595;</a></li>
        <li class="{% if sort == 'courses' %}active{% endif %}"><a href="?sort=courses&ct{{ category }}&city{{ city_id }}">课程数 &#8595;</a></li>
    </ul>
</div>

2.5 使用ajax异步提交表单(Model.Form提交表单)

在总url里面设置路由分发

 #课程机构url配置
url(r'^org/', include('organization.urls', namespace="org")),

在organization里新建子路由url

from django.conf.urls import url, include

from .views import OrgView, AddUserAskView

urlpatterns = [
    # 课程机构列表页
    url(r'^list/$', OrgView.as_view(), name="org_list"),
    url(r'^add_ask', AddUserAskView.as_view(), name="add_ask")
]

view.py

使用HttpResponse返回json数据

from django.http import HttpResponse
from .forms import UserAskForm

#表单的提交
class AddUserAskView(View):
    #用户添加咨询
    def post(self, request):
        userask_form = UserAskForm(request.POST)
        if userask_form.is_valid():

            user_ask = userask_form.save(commit=True)
            #返回异步操作ajax/json
            return HttpResponse("{'status':'success'}", content_type='application/json')
        else:
            return HttpResponse("{'status':'fail','msg':'添加出错'}", content_type='application/json')

在organization里面新建forms.py,使用ModelForm验证。

# _*_ coding: utf-8 _*_

import re
from django import forms
from operation.models import UserAsk

class UserAskForm(forms.ModelForm):

    class Meta:
        model = UserAsk
        fields = ['name', 'mobile', 'course_name']

    def clean_mobile(self):
        #验证手机号码是否合法
        mobile = self.cleaned_data['mobile']
        REGEX_MOBILE = "^1[358]d{9}$|^147d{8}$|^176d{8}$"
        p = re.compile(REGEX_MOBILE)
        if p.match(mobile):
            return mobile
        else:
            raise forms.ValidationError(u"手机号码非法", code="mobile_invalid")

重点在templates里面通过js的框架jquery配置ajax,实现数据的异步传输

{% block custom_js %}
<script>
    $(function(){
        $('#jsStayBtn').on('click', function(){
            $.ajax({
                cache: false,
                type: "POST",
                url:"{% url 'org:add_ask' %}",
                data:$('#jsStayForm').serialize(),
                async: true,
                success: function(data) {
                    console.log(data)
                    alert(data)
                    if(data.status == 'success'){
                        $('#jsStayForm')[0].reset();
                        alert("提交成功")
                    }else if(data.status == 'fail'){
                        $('#jsCompanyTips').html(data.msg)
                    }
                },
            });
        });
    })

</script>
{% endblock %}

数据库结果

2.6. 机构详情页功能实现

(1)机构首页

(2)机构课程

(3)机构介绍

(4)机构讲师

url.py

from django.conf.urls import url, include

from .views import OrgView, AddUserAskView, OrgHomeView, OrgCourseView, OrgDescView, OrgTeacherView

urlpatterns = [
    # 课程机构列表页
    url(r'^list/$', OrgView.as_view(), name="org_list"),
    url(r'^add_ask', AddUserAskView.as_view(), name="add_ask"),
    url(r'^home/(?P<org_id>d+)/$', OrgHomeView.as_view(), name="org_home"),
    url(r'^course/(?P<org_id>d+)/$', OrgCourseView.as_view(), name="org_course"),
    url(r'^desc/(?P<org_id>d+)/$', OrgDescView.as_view(), name="org_desc"),
    url(r'^teacher/(?P<org_id>d+)/$', OrgTeacherView.as_view(), name="org_teacher"),

]

view.py

#机构详情页
class OrgHomeView(View):
    #机构首页
    def get(self, request, org_id):
        current_page = "home"
        course_org = CourseOrg.objects.get(id=int(org_id))
        #用户收藏的展示(已收藏/收藏)
        has_fav = False
        if request.user.is_authenticated():
            if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
                has_fav = True

        all_courses = course_org.course_set.all()
        all_teachers = course_org.teacher_set.all()
        return render(request, 'org-detail-homepage.html', {
            'all_courses': all_courses,
            'all_teachers': all_teachers,
            'course_org': course_org,
            'current_page': current_page,
            'has_fav': has_fav
        })

class OrgCourseView(View):
    #机构课程介绍页
    def get(self, request, org_id):
        current_page = "course"
        course_org = CourseOrg.objects.get(id=int(org_id))
        has_fav = False
        if request.user.is_authenticated():
            if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
                has_fav = True

        all_courses = course_org.course_set.all()
        return render(request, 'org-detail-course.html', {
            'all_courses': all_courses,
            'course_org': course_org,
            'current_page': current_page,
            'has_fav': has_fav
        })

class OrgDescView(View):
    # 机构介绍页
    def get(self, request, org_id):
        current_page = "desc"
        course_org = CourseOrg.objects.get(id=int(org_id))
        has_fav = False
        if request.user.is_authenticated():
            if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
                has_fav = True

        all_courses = course_org.course_set.all()
        return render(request, 'org-detail-desc.html', {
            'all_courses': all_courses,
            'course_org': course_org,
            'current_page': current_page,
            'has_fav': has_fav
        })

class OrgTeacherView(View):
    #机构教师页
    def get(self, request, org_id):
        current_page = "teacher"
        course_org = CourseOrg.objects.get(id=int(org_id))
        has_fav = False
        if request.user.is_authenticated():
            if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2):
                has_fav = True

        all_teachers = course_org.teacher_set.all()
        return render(request, 'org-detail-teachers.html', {
            'all_teachers': all_teachers,
            'course_org': course_org,
            'current_page': current_page,
            'has_fav': has_fav
        })

 templates 新建org-list.html作为机构母页

新建母页org_base.html

<!DOCTYPE html>
<html>
{% load staticfiles %}
<head>
	<meta charset="UTF-8">
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
	<title>{% block title %}机构首页-慕学网{% endblock %}</title>
	<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
	<link rel="stylesheet" type="text/css" href="{% static 'css/animate.css' %}">
	<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'js/plugins/queryCity/css/cityLayout.css' %}">
    {% block custom_css %}{% endblock %}
    <script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/jquery-migrate-1.2.1.min.js' %}" type="text/javascript"></script>
    {% block custom_js %}{% endblock %}
</head>
<body>
<section class="headerwrap headerwrap2">
    <header>
		<div  class="header2 header">

               {% if request.user.is_authenticated %}
                <div class="top">
                    <div class="wp">
					<div class="fl"><p>服务电话:<b>18582854749</b></p></div>
					<!--登录后跳转-->
						<div class="personal">
                            <dl class="user fr">
                                <dd>鹏鹏<img class="down fr" src="/static/images/top_down.png"/></dd>
                                <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt>
                            </dl>
                            <div class="userdetail">
                            	<dl>
	                                <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt>
	                                <dd>
	                                    <h2>管理员</h2>
	                                    <p>root@qq.com</p>
	                                </dd>
                                </dl>
                                <div class="btn">
	                                <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
	                                <a class="fr" href="/logout/">退出</a>
                                </div>
                            </div>
                        </div>


				</div>
			</div>

                    {% else %}
                    <div class="top">
                        <a style="color:white" class="fr registerbtn" href="{% url 'register' %}">注册</a>
                        <a style="color:white" class="fr loginbtn" href="{% url 'login' %}">登录</a>

            {% endif %}


    <div class="middle companyheader">
        <div class="wp">
            <img class="fl" style="width: 112px;height: 103px" src="{{ MEDIA_URL }}{{course_org.image}}"/>
            <div class="head fl">
                <h1>
                    慕课网
                    <img src="{% static 'images/authentication.png' %}"/>
                    <img src="{% static 'images/gold.png' %}"/>
                </h1>
                <p class="fl">
                    <span class="fl" style="margin-top:8px;color:#848484;">推荐指数: </span>
                    <span class="precision company-credit" data-star-scope="5.0"></span>
                    <span class="key">5.0</span>
                </p>
            </div>
            <div class="btn fr collectionbtn  notlogin
                 "data-favid="22" data-fav-type="1">
                 {% if has_fav %}已收藏{% else %}收藏{% endif %}
            </div>

        </div>
    </div>
			</div>
    </header>
</section>
<section>
	<div class="wp">
		<ul  class="crumbs">
            <li><a href="index.html">首页</a>></li>
			<li><a href="{% url 'org:org_list' %}">课程机构</a>></li>
			<li>{% block page_path %}机构首页{% endblock %}</li>
		</ul>
	</div>
</section>

<section>
	<div class="wp list personal_list comp">
		<div class="left">
			<ul>
				<li class="{% ifequal current_page 'home' %}active2{% endifequal %}"><a href="{% url 'org:org_home' course_org.id %}">机构首页</a></li>
                <li class="{% ifequal current_page 'course' %}active2{% endifequal %}"><a href="{% url 'org:org_course' course_org.id %}">机构课程</a></li>
                <li class="{% ifequal current_page 'desc' %}active2{% endifequal %}"><a href="{% url 'org:org_desc' course_org.id %}">机构介绍</a></li>
                <li class="{% ifequal current_page 'teacher' %}active2{% endifequal %}"><a href="{% url 'org:org_teacher' course_org.id %}">机构讲师</a></li>
			</ul>
		</div>
{% block right_form %}
{% endblock %}
</section>

<!--sidebar start-->
<section>
    <ul class="sidebar">
        <li class="qq">
            <a target="_blank" href="http://wpa.qq.com/msgrd?v=3&uin=2023525077&site=qq&menu=yes"></a>
        </li>
        <li class="totop"></li>
    </ul>
</section>
<!--sidebar end-->
<!--header start-->
</div>
<!--弹出省省市-->
<script src="{% static 'js/selectUi.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'js/plugins/laydate/laydate.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'js/plugins/queryCity/js/public.js' %}" type="text/javascript"></script>

<script type="text/javascript" src="{% static 'js/plugins/jquery.raty.js' %}"></script>
<script type="text/javascript">
<!--收藏分享-->
function add_fav(current_elem, fav_id, fav_type){
    $.ajax({
        cache: false,
        type: "POST",
        url:'{% url "org:add_fav" %}',
        data:{'fav_id':fav_id, 'fav_type':fav_type},
        async: true,
        beforeSend:function(xhr, settings){
            xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
        },
        success: function(data) {
            if(data.status == 'fail'){
                if(data.msg == '用户未登录'){
                    window.location.href="/login/";
                }else{
                    current_elem.text(data.msg)
                }

            }else if(data.status == 'success'){
                current_elem.text(data.msg)
            }
        },
    });
}

$('.collectionbtn').on('click', function(){
    add_fav($(this), {{ course_org.id }}, 2);
});

$(function(){
    var $precision = $('.precision'),
        score = $precision.attr('data-star-scope'),
        option =  {
                    half		: true,
                    path		: '{% static 'images/' %}',
                    precision	: true,
                    size		: 24,
                    starOff		: 'g_star.png',
                    starOn		: 'r_star.png',
                    starHalf	: 'h_star.png',
                    hints       : ['极差', '差', '一般', '好评', '非常满意'],
                    noRatedMsg  : '暂时还未获得评价!',
                    readOnly    : true,
                    score       : score
                };
    $precision.raty(option);

    $('.jsFavBtn').on('click', function(){
        var type = $(this).attr('data-fav-type');
        if(type == '1'){
            favPraise($(this), 'fav' ,1 , '收藏');

        }else if(type == '3'){
            favPraise($(this), 'fav' ,3 );

        }else if(type == '11'){
            favPraise($(this), 'pra', 1);

        }else if(type == '4'){
            favPraise($(this), 'fav' ,4 );

        }
    });
})
</script>


<script type="text/javascript">
$(function() {
    $('.recordbtn1').click(function(){
        $('.recordbox1').show();
    });
    $('.recordbtn2').click(function(){
        $('.recordbox2').show();
    });

    $('.imgslide').unslider({
        speed: 500,               //  The speed to animate each slide (in milliseconds)
        delay: 3000,              //  The delay between slide animations (in milliseconds)
        complete: function() {},  //  A function that gets called after every slide animation
        keys: true,               //  Enable keyboard (left, right) arrow shortcuts
        dots: true,               //  Display dot navigation
        fluid: false              //  Support responsive design. May break non-responsive designs
    });
    var unslider = $('.imgslide').unslider();
    $('.unslider-arrow').click(function() {
        var fn = this.className.split(' ')[1];
        unslider.data('unslider')[fn]();
    });
});
</script>

</body>
</html>

(1)机构首页org-detail-homepage.html

{% extends 'org_base.html' %}
{% block title %}机构首页{% endblock %}
{% block page_path %}机构首页{% endblock %}
{% block right_form %}
<div class="right companycenter layout grouping" >
		<div class="head">
			<h1>全部课程</h1>
			<a class="green fr more" href="org-detail-course.html">查看更多  >  </a>
		</div>
		<div class="brief group_list">
            {% for course in all_courses %}
             <div class="module1_5 box">
                    <a href="course-detail.html"><img width="214" src="{{ MEDIA_URL }}{{ course.image }}"/></a>
                    <div class="des">
                        <a href="course-detail.html"><h2>{{ course.name }}</h2></a>
                        <span class="fl">课时:<i class="key">{{ course.learn_time }}</i></span>
                        <span class="fr">参加人数:{{ course.students }}</span>
                    </div>
                    <div class="bottom">
                        <span class="fl">{{ course.course_org.name }}</span>
                         <span class="star fr  notlogin
                            " data-favid="13"  data-fav-type="4">
                            {{ course.fav_nums }}
                        </span>
                    </div>
                </div>
            {% endfor %}


		</div>
	</div>
<div class="right companycenter layout" >
    <div class="head">
        <h1>机构教师</h1>
        <a class="green fr more" href="org-detail-teachers.html">查看更多  >  </a>
    </div>
    {% for teacher in all_teachers %}
        <div class="diarys">
        <div class="module5 share company-diary-box" style="padding:10px 0;">
            <div class="left">
                <img class="pic" src="{{ MEDIA_URL }}{{ teacher.image }}"/>
                <p>昵称:{{ teacher.name }}</p>
            </div>
            <div class="right">
                <div class="top">
                    <div class="fl">
                        <a href=""><h1>java开发教程</h1></a>
                        <span>发表于:2015-10-12</span>
                    </div>
                </div>
                <div class="middle" style="border-bottom:0;">课程介绍</div>
            </div>
        </div>
    </div>
    {% endfor %}

</div>
<div class="right companycenter layout" >
    <div class="head">
        <h1>机构介绍</h1>
        <a class="green fr more" href="org-detail-desc.html">查看更多  >  </a>
    </div>
    <div class="cont">&nbsp; &nbsp;{{ course_org.desc }}<
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_41988628/article/details/85386072
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-13 15:36:35
  • 阅读 ( 1455 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢