通过简单小例子学习django框架的相关操作

django是最近比较流行的一种基于Python的web框架,相比于比较有名的ssm好spring boot等java框架,我觉他它的操作更加简单实用。

MVC和MTV模式

著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器©,视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起。
模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器©接受用户的输入调用模型和视图完成用户的请求。
MVC是一种使用最广泛的设计模式,它使得各部分功能都能独立开发,做界面的可以专注于视图界面的开发,做后台的可以专注于业务逻辑开发,互不影响。

djang使用的MTV模式与MVC模式并无本质上区别,核心思想也是将视图和业务逻辑拆分解耦,使得各部分工作可以独立开发,互不影响。
MTV模式为M(模型)T(模板)V(视图)模式,模型负责与数据库交互,模板中定义了显示给用户的HTML界面,视图专注于负责业务逻辑,此外还有一个URL分发器,它的作用在于将不同的url请求分发给view中不同的方法处理。

django相关的命令

django-admin.py startproject project_name #新建Django项目
python manage.py startapp app_name #新建app

#创建数据库时需要执行两条命令
python manage.py makemigrations # 1. 创建更改的文件
python manage.py migrate # 2. 将生成的py文件应用到数据库

python manage.py runserver ip:port #启动服务
python manage.py flush #清空数据库
python manage.py #查询更多命令
基本常识介绍到这里,下面来看需求

功能需求

这个小例子很简单,主要为了实现下面3个需求:

  • 用户登录与注册
  • 用户登录成功后可以展示所有用户信息
  • 如果没有检测到用户登录记录,则跳转到登录界面

为此数据库创建两张表就行了,一张登录信息表,用于保存用户名和密码,另一张用户信息表,用于保存用户基本信息(姓名,年龄,地址,性别)。
数据库使用MySQL,也可以用sqlite,使用是sqlite不需要专门安装数据库引擎,比MySQL方便不少。
页面的话有三个页面,分别是登录界面,注册界面和展示用户基本信息的界面。

这里先把完整的项目结构放上来,后面再慢慢解释每一部分的含义:
在这里插入图片描述
好了,首先要先创建一个django项目,使用命令django-admin.py startproject project_name
在这里插入图片描述
在这里插入图片描述
执行完命令后路径下就多了一个users文件夹,这就是我们创建好的django项目,简单吧!
然后我们使用pycharm打开,后面的操作都在pycharm中进行。
最初的项目是这样的:
在这里插入图片描述
manage是执行文件的入口,启动服务,数据库迁移等操作都需要执行这个脚本
urls.py就是之前所说的url分发器,看一下里面的代码:

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

初始状态只有一个默认的url
settings.py用于配置项目的基本配置,包括,数据库引擎,子项目,模板路径等等。主要用到的就是这两个脚本。

然后我们启动服务,看一下效果,在pycharm终端上使用命令python manage.py runserver
在这里插入图片描述
在这里插入图片描述
看到这句话,就表示服务启动成功了,现在可以通过127.0.0.0:8000访问项目,这里默认的端口号为8000,如果想改可以在命令后面加上表示端口的参数,如:

Python manage.py runserver 127.0.0.1:8080

这样就可以在8080端口访问了
在这里插入图片描述
通过urls.py中定义的url就可以访问到相应界面了。

下面来创建自己的app,使用命令Python manage.py startapp User
在这里插入图片描述
执行成功后,项目里面会多了一个User的目录:
在这里插入图片描述
主要用到的有models.py和views.py两个脚本,分别代表模型(M)和视图(V)。
那还有一个模板(T)跑哪去了?我们可以自己创建一个templates目录,用于保存相关的模板文件。注意需要在settings.py中配置模板路径。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'template')],
        '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',
            ],
        },
    },
]

同时,也要将创建的项目加入进去,最后一个User就是刚刚创建的app:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'User'
]

如果不考虑数据库的话,User这个APP就已经能用了,接下来先尝试写个简单的views方法,不配置数据库。
在views.py中写下下面代码:

def index(request):
    return render(request,'index.html')

request表示用户传回的request请求,return render(request,‘index.html’)这句返回一个HttpResponse对象,就是我们的index.html页面,这里需要导入两个模块

from django.shortcuts import render,HttpResponse

index.html这样写:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>12345</h1>
</body>
</html>

然后需要在urls.py中分配url:

from django.contrib import admin
from django.urls import path
from User import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    ]

这里的views.index就是我们在views,py中写好的业务逻辑

访问看看:
在这里插入图片描述
这就成功了。
所以总结一下,如果要增加新的url请求的话,至少需要更改三个地方:

  • views.py增加业务逻辑
  • template增加页面(当然这里也可以直接返回一个HTTPResponse对象,后面再讲)
  • urls.py分配url

数据库创建及相关操作

接下来看数据库的配置
我们使用MySQL数据库,这需要先安装MySQL引擎,Python3中需要安装pymysql这个第三方库

pip install pymysql

然后在__init__.py中写入如下代码:

import pymysql
pymysql.install_as_MySQLdb()

简单说一下这里可能出现的错误

  • NO module named ‘pymysql’
    这种错误的原因有两个,第一个在你的项目目录下并没有安装pymysql,打开File->settings->project users->projext interpreter,查看安装的第三方库。
    在这里插入图片描述
    如果没有的话,在项目目录下重新安装一下就好了。
    第二个是因为使用Python2的话会导致吧pymysql安装到Python2的sitepackge目录下,需要把Python2卸载掉。
  • mysql django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required;
    在这里插入图片描述
    将site-packages目录下这个脚本的35和36行注释掉,报错解决。
  • ‘str’ object has no attribute ‘decode’
    将报错脚本中的decode改为encode,报错解决

以上三个报错是我在搭建过程中遇到的错误,花了不少时间才解决,这个MySQL真是挺坑的。
然后开始连接数据库,首先在settings.py中配置MySQL数据库连接:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   # 数据库引擎
        'NAME': 'mydb',         # 你要存储数据的库名,事先要创建之
        'USER': 'root',         # 数据库用户名
        'PASSWORD': '1234',     # 密码
        'HOST': 'localhost',    # 主机
        'PORT': '3306',         # 数据库使用的端口
    }
}

然后在models.py中创建我们要创建的数据库表,这里直接创建对象,继承models.Model就好了,不需要去数据库中创建:

from django.db import models

# Create your models here.
class login_info(models.Model):
    username = models.CharField(max_length=50)
    password = models.CharField(max_length=50)


class user_info(models.Model):
    name = models.CharField(max_length=50)
    age = models.IntegerField()
    addr = models.CharField(max_length=100)
    sex = models.CharField(max_length=10)

这里的CharField表示数据库字段类型
然后执行这两条命令:

python manage.py makemigrations  # 1. 创建更改的文件
python manage.py migrate  # 2. 将生成的py文件应用到数据库

在这里插入图片描述
执行完之后,数据库中就会自动生成以上的表格,最后两张user开头的就是我们创建的表。
这里简单说一下django对数据库的增删改查操作,想要进一步了解的可以看官方文档

增:

s = models.tablename(name='123',age='34')
s.save()

s.save()一定不能丢,否则不会生效
相当于

INSERT INTO tablename SET name = '123', age= '34';

删:

Entry.objects.filter(pub_date__year=2005).delete()  #delete from Entry where pub_data__year = '2005'
Entry.objects.all().delete()  #这是有可能会坐牢的操作

改:

product = Product.objects.get(name='Venezuelan Beaver Cheese')
product.number_sold += 1
product.save()

#update Product set number_sold = number_sold+1 where name = 'Venezuelan Beaver Cheese'

查:

models.UserInfo.objects.all()
models.UserInfo.objects.all().values('user')    #只取user列
models.UserInfo.objects.all().values_list('id','user')    #取出id和user列,并生成一个列表
models.UserInfo.objects.get(id=1)
models.UserInfo.objects.get(user='yangmv')

接下来可以写业务逻辑,首先登陆:
views.py

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username',None)
        password = request.POST.get('password',None)
        if check_passwd(username,password):
        	global loginFlag
            loginFlag = True
            return redirect(show)
        else:
            html = '''
                    <p>请检查用户名密码是否正确<p>
                    <a href='/login/'>返回登录<a>
                '''
            return HttpResponse(html)
    else:
        return render(request,'login.html')

loginFlag 保存的是登录信息,是全局变量
check_passwd方法是这样的:

def check_passwd(username,password):
    try:
        result = login_info.objects.get(username=username)
        if result.password == password:
            return True
    except:
        return False

解释一下为啥要用try except,因为如果没有查找到username的话,脚本会抱一个异常,而不是返回None值,这会导致代码不能往下执行,所以这里用异常来处理。
template :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <form name="Form1" action="/login/" method="post">
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        <a href="javascript:document.Form1.submit();">登录</a>
        <a href="/register/">注册</a>
        {% csrf_token %}
    </form>
</body>
</html>

{% csrf_token %}这个不能丢,这是为了防止跨站攻击的,每个post请求最后都要加上。
urls.py

path('login/', views.login),

然后注册:
views.py

def register(request):
    if request.method == 'POST':

        username = request.POST.get('username',None)
        password = request.POST.get('password',None)
        confirmpasswd = request.POST.get('confirmPwd',None)
        age = request.POST.get('age',None)
        address = request.POST.get('address',None)
        sex = request.POST.get('sex',None)

        if password == confirmpasswd:
            if add_loginInfo(username,password):
                add_userInfo(username,age,address,sex)
                html = '''
                        <p>注册成功<p>
                        <a href='/login/'>返回登录<a>
                    '''
                return HttpResponse(html)
            else:
                html = '''
                            <p>用户名已被注册,请重新输入用户名<p>
                            <a href='/register/'>返回注册<a>
                        '''
                return HttpResponse(html)
        else:
            html = '''
                <p>密码不一致,请重新输入<p>
                <a href='/register/'>返回注册<a>
            '''
            return HttpResponse(html)
    else:
        return render(request,'register.html')

add_loginInfo和add_userInfo:

def add_loginInfo(username,password):
    try:
        result = login_info.objects.get(username=username)
        return False
    except:
        pass
    t = login_info(username=username, password=password)
    t.save()
    return True

def add_userInfo(name,age,addr,sex):
    u = user_info(name=name,age=age,addr=addr,sex=sex)
    u.save()

template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Register</title>
    <style type="text/css">
        .s
        {
            display: block;
            float: left;
            width: 150px;
            height: 20px;
        }
    </style>
</head>
<body>
    <form action="/register/" method="post" name="form2">
        <span class="s">username:</span><input type="text" name="username"><br>
        <span class="s">password:</span><input type="password" name="password"><br>
        <span class="s">confirmPassword:</span><input type="password" name="confirmPwd"><br>
        <br><br>
        <span class="s">age:</span><input type="text" name="age"><br>
        <span class="s">address:</span><input type="text" name="address"><br>
        <span class="s">sex:</span><input type="radio" name="sex" value="male">男
        <input type="radio" name="sex" value="female">女<br>
        <input type="submit" name="提交" value="注册">
        {% csrf_token %}
    </form>
</body>
</html>

urls.py

path('register/',views.register),

最后展示用户信息:
views.py

def show(request):
    if not loginFlag:
        return redirect(login)
    data = {}
    UserInfo = user_info.objects.all()
    data['UserInfo'] = UserInfo
    return render(request,'show.html',context=data)

这里的redirect是一种重定向的方法,如果没有登录就返回登录界面先登录,否则不能查看用户信息。
templates:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Show</title>
</head>
<body>
    <ul>
        {% for item in UserInfo %}
            <li>
                <span>{{ item.name }}</span>
                <span>{{ item.age }}</span>
                <span>{{ item.addr }}</span>
                <span>{{ item.sex }}</span>
            </li>
        {% endfor %}
    </ul>
</body>
</html>

这里解释一下for标签的使用,可以看到在show方法中传入了一个context=data参数,这个参数传入的是一个字典对象,用于展示在页面上的数据。这里将从数据库获取到的userInfo数据传入页面中,然后页面中可以用for标签展示,注意这里最好严格按照我的写法:

{% for item in UserInfo %}
          
{% endfor %}

不要随便的增加或者减少空格,否则会有意想不到的错误发生。

urls.py

path('show/',views.show)

现在功能基本完成了,来看一下效果:
在这里插入图片描述
登录界面
在这里插入图片描述
用户名密码输错的情况
在这里插入图片描述
输入成功后显示用户信息
在这里插入图片描述
注册界面
在这里插入图片描述
密码不一致
在这里插入图片描述
用户名被注册
在这里插入图片描述
注册成功
在这里插入图片描述
多了一条信息,就是刚刚注册的那个
如果不登录,直接输入http://127.0.0.1:8000/show/的话,会跳转到登录界面。

这个小例子还有许多可以优化的地方,比如增加退出登录功能,密码保存使用加密算法加密等等,有人如果有兴趣可以当做练习,本人对前端不太了解,所以页面几乎没有css样式,后面如果有时间再做优化。

完整项目地址:https://github.com/cchhgithub/django_user

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值