zoukankan      html  css  js  c++  java
  • 创建django项目完整实例

    虚拟环境搭配

    安装和配置

    安装虚拟环境的命令:

    1)sudo pip install virtualenv #安装虚拟环境

    2)sudo pip install virtualenvwrapper #安装虚拟环境扩展包

    3)编辑家目录下面的.bashrc文件,添加下面两行。

    export WORKON_HOME=$HOME/.virtualenvs

    source /usr/local/bin/virtualenvwrapper.sh

    4)使用source .bashrc使其生效一下。

    使用

    创建python3虚拟环境:

    mkvirtualenv -p python3 bj19  # bj19是虚拟环境名

    进入虚拟环境工作:

    workon 虚拟环境名

    查看机器上有多少个虚拟环境:

    workon 空格 + 两个tab键

    退出虚拟环境:

    deactivate

    删除虚拟环境:

    rmvirtualenv 虚拟环境名

    虚拟环境下安装包的命令:

    pip install 包名

    注意:不能使用sudo pip install 包名,这个命令会把包安装到真实的主机环境上而不是安装到虚拟环境中。

    查看虚拟环境中安装了哪些python包:

    pip list  
    pip freeze

    安装django环境:

    pip install django==1.8.2

    创建项目

    建立文件夹

    mkdir bj19  # bj19是文件夹名 随便起

    进入bj19 创建应用包

    python manage.py startapp booktest  # booktest是应用名,可以随便起

    更改settings.py设置

    # 注册应用
    INSTALLED_APPS = (
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'booktest',  # 注册创建的booktest应用 如果没有这个 创建数据库会报NO changes 错误
    )
    ....
    # 模板配置
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 指定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',
                ],
            },
        },
    ]
    ....
    # 数据库配置
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',  # 指定用什么数据库
            'NAME': 'test1',  # 指定数据库名
            'USER': 'root',  # 数据库账号
            'PASSWORD': 'mysql',  # 数据库密码
            'HOST': 'localhost',  # 数据库IP 本机用localhost
            'PORT': 3306,  # 端口
        }
    }
    ....
    # 本地化配置
    LANGUAGE_CODE = 'zh-hans'  # 本地化语言
    
    TIME_ZONE = 'Asia/Shanghai'  # 本地化时间
    ....
    # 静态资源配置
    STATIC_URL = '/static/'
    STATICFILES_DIR=[os.path.join(BASE_DIR, 'static')]  # 静态资源存放路径

    创建模板文件夹 对应应用名在templates创建子目录

     创建静态资源文件包

     创建数据库test1

    create database test1 charset=utf8;

    项目中引用pymysql

    test1/__init__.py文件中

    import pymysql
    pymysql.install_as_MySQLdb()

    建表

    booktest/models.py中

    from django.db import models
    from datetime import date
    # Create your models here.
    class BookInfo(models.Model):
        '''图书模型类'''
        # 书名
        # btitle = models.CharField(verbose_name='书名', max_length=20)  # verbose_name= 在admin后台显示的标题 max_length=最大长度
        btitle = models.CharField('书名', max_length=20)  # 如果标题放在第一位 则可以省略verbose_name=
        # 出版时间
        bpub_date = models.DateField()
        # 阅读量
        bread = models.IntegerField(default=0)  # default 设置默认值
        # 评论数
        bcomment = models.IntegerField(default=0)
        # 是否删除
        isDelete = models.BooleanField(default=False)
    
        # 定义数据表名称--元选项
        class Meta:
            # 指定生成的数据表名
            db_table = 'bookinfo'
    
    
    class HeroInfo(models.Model):
        '''英雄模型类'''
        # 姓名
        hname = models.CharField('英雄', max_length=20)
        # 性别
        hgender = models.BooleanField(default=False)
        # 功夫
        hcomment = models.CharField('功夫', max_length=128)
        # 关联书名
        hbook = models.ForeignKey('BookInfo')
        # 是否删除
        isDelete = models.BooleanField(default=False)
    
        # 数据表名
        class Meta:
            db_table = 'heroinfo'
    
    
    class AreaInfo(models.Model):
        '''地域模型类'''
        # 地名
        atitle = models.CharField('地名', max_length=20)
        # 自关联pid
        aParent = models.ForeignKey('self', null=True, blank=True)
    
        # 表名
        class Meta:
            db_table = 'areainfo'

    迁移

    python manage.py makemigrations
    python manage.py migrate

    报错

    解决方案:

    看一下settings.py文件 apps中有没有添加 booktest

    迁移成功

     查看数据库

     默认值并不在数据库层面生效,而是在django创建对象时生效。

    图书表结构

    表heroinfo结构如下:

     Django框架会根据关系属性生成一个关系字段,并创建外键约束。

    测试数据
    在数据库命令行中,复制如下语句执行,向booktest_bookinfo表中插入测试数据:

    insert into bookinfo(btitle,bpub_date,bread,bcomment,isDelete) values
    ('射雕英雄传','1980-5-1',12,34,0),
    ('天龙八部','1986-7-24',36,40,0),
    ('笑傲江湖','1995-12-24',20,80,0),
    ('雪山飞狐','1987-11-11',58,24,0);

    向booktest_heroinfo表中插入测试数据:

    insert into heroinfo(hname,hgender,hbook_id,hcomment,isDelete) values
    ('郭靖',1,1,'降龙十八掌',0),
    ('黄蓉',0,1,'打狗棍法',0),
    ('黄药师',1,1,'弹指神通',0),
    ('欧阳锋',1,1,'蛤蟆功',0),
    ('梅超风',0,1,'九阴白骨爪',0),
    ('乔峰',1,2,'降龙十八掌',0),
    ('段誉',1,2,'六脉神剑',0),
    ('虚竹',1,2,'天山六阳掌',0),
    ('王语嫣',0,2,'神仙姐姐',0),
    ('令狐冲',1,3,'独孤九剑',0),
    ('任盈盈',0,3,'弹琴',0),
    ('岳不群',1,3,'华山剑法',0),
    ('东方不败',0,3,'葵花宝典',0),
    ('胡斐',1,4,'胡家刀法',0),
    ('苗若兰',0,4,'黄衣',0),
    ('程灵素',0,4,'医术',0),
    ('袁紫衣',0,4,'六合拳',0);

     后台管理

    本地化设置已经在settings.py设置好了

    创建后台管理账号

    python manage.py createsuperuser

     运行项目 然后登陆后台

    #python manage.py runserver 服务器IP:端口
    python manage.py runserver 192.168.121.130:8000

     登录后台查看

    192.168.121.130:8000/admin

    注册和登录

    添加用户表

    class AdminInfo(models.Model):
        # 管理员
        user = models.CharField(max_length=20, unique=True)
        # 密码
        password = models.CharField(max_length=128)
        # 是否删除
        isDelete = models.BooleanField(default=False)

    创建regist.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="/static/js/jquery-1.12.4.min.js"></script>
    
    </head>
    <body>
    
    <form action="/regist_handle" method="post">
        {% csrf_token %}
        <lable>账号:</lable>
        <input type="text" name="user"><br>
        <lable>密码:</lable>
        <input type="password" name="password">
        <br>
        <input type="text" name="verify_code" placeholder="请输入验证码">
        <img src="/verify_code" onclick="this.src='/verify_code?'+ Math.random()" alt="" ><br>  <-- 点击更换验证码 !-->
        <input type="submit" value="注册">
    </form>
    </body>
    </html>

    注册及验证码的视图函数views.py

    def regist(request):
        return render(request, 'booktest/regist.html')
    
    def regist_handle(request):
        user = request.POST.get('user')  # POST或GET要大写
        password = request.POST.get('password')
        verifycode = request.POST.get('verify_code')
    
        if verifycode != request.session['verifycode']:
            return HttpResponse('验证码不正确')
        u = AdminInfo()
        u.user = user
        u.password = password
        u.save()
        return redirect('/login')
    
    
    # 验证码
    from PIL import Image, ImageDraw, ImageFont
    from django.utils.six import BytesIO
    def verify_code(request):
        #引入随机函数模块
        import random
        #定义变量,用于画面的背景色、宽、高
        bgcolor = (random.randrange(20, 100), random.randrange(
            20, 100), 255)
        width = 100
        height = 25
        #创建画面对象
        im = Image.new('RGB', (width, height), bgcolor)
        #创建画笔对象
        draw = ImageDraw.Draw(im)
        #调用画笔的point()函数绘制噪点
        for i in range(0, 100):
            xy = (random.randrange(0, width), random.randrange(0, height))
            fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
            draw.point(xy, fill=fill)
        #定义验证码的备选值
        str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
        #随机选取4个值作为验证码
        rand_str = ''
        for i in range(0, 4):
            rand_str += str1[random.randrange(0, len(str1))]
        #构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
        font = ImageFont.truetype('FreeMono.ttf', 23)
        #构造字体颜色
        fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
        #绘制4个字
        draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
        draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
        draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
        draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
        #释放画笔
        del draw
        #存入session,用于做进一步验证
        request.session['verifycode'] = rand_str
        #内存文件操作
        buf = BytesIO()
        #将图片保存在内存中,文件类型为png
        im.save(buf, 'png')
        #将内存中的图片数据返回给客户端,MIME类型为图片png
        return HttpResponse(buf.getvalue(), 'image/png')

    注册路由urls.py

        url(r'regist$', views.regist),
        url(r'regist_handle$', views.regist_handle),
        url(r'verify_code', views.verify_code),

    登录页面login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/login_check" method="post">
        {% csrf_token %}
        <lable>账号:</lable>
        <input type="text" name="user"><br>
        <lable>密码:</lable>
        <input type="password" name="password">
        <br>
    
        <input type="submit" value="登陆">
    </form>
    </body>
    </html>

    登录的视图函数views.py

    # 登陆页面
    def login(request):
       return render(request, 'booktest/login.html')
    
    # 登陆校验
    def login_check(request):
    
        user = request.POST.get('user')
        password = request.POST.get('password')
        userinfo = AdminInfo.objects.filter(user=user)  # filter取的是一个questset集 要加get()才能取到值 如果不用filter()用get()取值的话 为空的时候会报错
        if not userinfo:
            return HttpResponse("无数据")
        else:
            userinfo = userinfo.get()  # QuestSet无法直接读取值 要用get()取值
        if user==userinfo.user and password==userinfo.password:
            request.session['isLogin'] = True
            request.session['user'] = user
            return redirect('/index')
        else:
            return redirect('/login')

    注册路由urls.py

        url(r'^login$', views.login),
        url(r'^login_check$', views.login_check),

     登录校验装饰器views.py

    # 校验是否登录,如果没登录返回登录页面
    def login_check(func):
        def wapper(request, *view_args, **view_kwarga):
            if not request.session.has_key('isLogin'):
                return redirect('/login')
            return func(request, *view_args, **view_kwarga)
        return wapper

     上传图片

    定义模型类models.py

    class Uploads(models.Model):
        '''图片模型类'''
        pic = models.ImageField(upload_to='booktest') # upload_to= 上传到哪个文件夹

    设置路径settings.py

    UPLOAD_ROOT = os.path.join(BASE_DIR, 'static/upload')  # 没有中括号

    上传页面pic_upload.html

    在模板中定义上传表单,要求如下:

    • form的属性enctype="multipart/form-data"
    • form的method为post
    • input的类型为file
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="upload_handle" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="file" name="pic"><br>
        <input type="submit" value="上传">
    </form>
    </body>
    </html>

    上传和处理的视图函数 views.py

    # 上传页面
    def pic_upload(request):
        return render(request, 'booktest/pic_upload.html')
    
    # 上传处理
    from django.conf import settings  # 为了导入上传路径
    def upload_handle(request):
        pic = request.FILES.get('pic')  # 图片用FILES.get() 接收
        print(pic.name)
        p = Uploads()
        p.pic = 'booktest/%s' % pic.name  # 保存到数据库
        p.save()
        pname = '%s/booktest/%s' % (settings.UPLOAD_ROOT, pic.name)
        with open(pname, 'wb') as f:  # 写入到指定文件夹
            for content in pic.chunks():  # pic.chunks() 一段一段读取
                f.write(content)
        return HttpResponse('ok')

     分页

    Paginator类对象的属性:

    属性名

    说明

    num_pages

    返回分页之后的总页数

    page_range

    返回分页后页码的列表

    Paginator类对象的方法:

    方法名

    说明

    page(self, number)

    返回第number页的Page类实例对象

     

    Page类对象的属性:

    属性名

    说明

    number

    返回当前页的页码

    object_list

    返回包含当前页的数据的查询集

    paginator

    返回对应的Paginator类对象

     

    Page类对象的方法:

    属性名

    说明

    has_previous

    判断当前页是否有前一页

    has_next

    判断当前页是否有下一页

    previous_page_number

    返回前一页的页码

    next_page_number

    返回下一页的页码

    Paginator类实例对象

    • 方法_init_(列表,int):返回分页对象,第一个参数为列表数据,第二个参数为每页数据的条数。
    • 属性count:返回对象总数。
    • 属性num_pages:返回页面总数。
    • 属性page_range:返回页码列表,从1开始,例如[1, 2, 3, 4]。
    • 方法page(m):返回Page类实例对象,表示第m页的数据,下标以1开始。

    Page类实例对象

    • 调用Paginator对象的page()方法返回Page对象,不需要手动构造。
    • 属性object_list:返回当前页对象的列表。
    • 属性number:返回当前是第几页,从1开始。
    • 属性paginator:当前页对应的Paginator对象。
    • 方法has_next():如果有下一页返回True。
    • 方法has_previous():如果有上一页返回True。
    • 方法len():返回当前页面对象的个数。

    创建视图page_test.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1></h1>
    <ul>
        {% for p in page %}
            <li>{{ p.atitle }}</li>
        {% endfor %}
    </ul>
    
    {#页码#}
    {#判断是否有上一页#}
    {% if page.has_previous %}
        <a href="/page_test/{{ page.previous_page_number }}">《上一页</a>
    {% endif %}
    {% for pindex in plist %}
    {#    判断当前页 撤销当前页a标签#}
        {% if pindex == page.number %}
            {{ pindex }}
        {% else %}
            <a href="/page_test/{{ pindex }}">{{ pindex }}</a>
        {% endif %}
    {% endfor %}
    {#判断是否有下一页#}
    {% if page.has_next %}
        <a href="/page_test/{{ page.next_page_number }}">下一页》</a>
    {% endif %}
    </body>
    </html>

    分页的视图函数views.py

    from django.core.paginator import Paginator # 分页需导入paginator包
    def page_test(request, pindex):  # 红字参数与路由要一致
        # 查询所有省的名称
        prov_list = AreaInfo.objects.filter(aParent__isnull=True)
        print(prov_list)
        # 分页 每页显示10条内容
        provs = Paginator(prov_list,10)
        # 如果当前没有传递页码信息,则认为是第一页,这样写是为了请求第一页时可以不写页码
        if pindex=='':
            pindex = 1
        else:
            # 通过url匹配的参数都是字符串类型,转换成int类型
            pindex = int(pindex)
        # 获取第pIndex页的数据
        page = provs.page(pindex)
        # 获取所有的页码信息
        plist = provs.page_range
        return render(request, 'booktest/page_test.html', {'page':page, 'plist':plist})

    路由urls.py

    url(r'page_test/(?P<pindex>d*)$', views.page_test), # 红字部分要和views.py 中视图函数的形参保持一致

     三级联动

    创建视图areas.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>省市县选择案例</title>
        <script src="/static/js/jquery-1.12.4.min.js"></script>
        <script>
            $(function () {
                // 发起一个ajax请求 /prov,获取所有省级地区的信息
                // 获取信息,使用get
                // 涉及到信息修改,使用post
                $.get('/prov', function (data) {
                    // 回调函数
                    // 获取返回的json数据
                    res = data.data
                    // 获取prov下拉列表框
                    prov = $('#prov')
                    // 变量res数组,获取每一个元素:[地区id, 地区标题]
                    /*
                    for(i=0; i<res.length; i++){
                        id = res[i][0]
                        atitle = res[i][1]
    
                        option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                        // 向prov下拉列表框中追加元素
                        prov.append(option_str)
                    }*/
                    $.each(res, function (index, item) {
                        id = item[0]
                        atitle = item[1]
                        option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                        // 向prov下拉列表框中追加元素
                        prov.append(option_str)
                    })
                })
    
                // 绑定prov下拉列表框的change事件,获取省下面的市的信息
                $('#prov').change(function () {
                    // 发起一个ajax请求 /city,获取省下面市级地区的信息
                    // 获取点击省的id
                    prov_id=$(this).val()
                    $.get('/city'+prov_id, function (data) {
                        // 获取返回的json数据
                        res = data.data
                        // 获取city下拉列表框
                        city = $('#city')
                        // 清空city下拉列表框
                        city.empty().append('<option>---请选择市---</option>')
                        // 获取dis下拉列表框
                        dis = $('#dis')
                        // 清空dis下拉列表框
                        dis.empty().append('<option>---请选择县---</option>')
                        // 变量res数组,获取每一个元素:[地区id, 地区标题]
                        // 遍历取值添加到city下拉列表框中
                        $.each(res, function (index, item) {
                            id = item[0]
                            atitle = item[1]
                            option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                            // 向city下拉列表框中追加元素
                            city.append(option_str)
                        })
                    })
                })
    
                 // 绑定city下拉列表框的change事件,获取市下面的县的信息
                $('#city').change(function () {
                    // 发起一个ajax请求 /dis,获取市下面县级地区的信息
                    // 获取点击市的id
                    city_id=$(this).val()
                    $.get('/dis'+city_id, function (data) {
                        // 获取返回的json数据
                        res = data.data
                        // 获取dis下拉列表框
                        dis = $('#dis')
                        // 清空dis下拉列表框
                        dis.empty().append('<option>---请选择县---</option>')
                        // 变量res数组,获取每一个元素:[地区id, 地区标题]
                        // 遍历取值添加到dis下拉列表框中
                        $.each(res, function (index, item) {
                            id = item[0]
                            atitle = item[1]
                            option_str = '<option value="'+id + '">'+ atitle+ '</option>'
                            // 向dis下拉列表框中追加元素
                            dis.append(option_str)
                        })
                    })
                })
            })
        </script>
    </head>
    <body>
    <select id="prov">
        <option>---请选择省---</option>
    </select>
    <select id="city">
        <option>---请选择市---</option>
    </select>
    <select id="dis">
        <option>---请选择县---</option>
    </select>
    </body>
    </html>

    视图函数views.py

    # /areas
    def areas(request):
        '''省市县选中案例'''
        return render(request, 'booktest/areas.html')
    
    
    # /prov
    def prov(request):
        '''获取所有省级地区的信息'''
        # 1.获取所有省级地区的信息
        areas = AreaInfo.objects.filter(aParent__isnull=True)
    
        # 2.变量areas并拼接出json数据:atitle id
        areas_list = []
        for area in areas:
            areas_list.append((area.id, area.atitle))
    
        # 3.返回数据
        return JsonResponse({'data':areas_list})
    
    
    def city(request, pid):
        '''获取pid的下级地区的信息'''
        # 1.获取pid对应地区的下级地区
        # area = AreaInfo.objects.get(id=pid)
        # areas = area.areainfo_set.all()
        areas = AreaInfo.objects.filter(aParent__id=pid)
    
        # 2.变量areas并拼接出json数据:atitle id
        areas_list = []
        for area in areas:
            areas_list.append((area.id, area.atitle))
    
        # 3.返回数据
        return JsonResponse({'data': areas_list})

    路由配置urls.py

        url(r'^areas$', views.areas), # 省市县选中案例
        url(r'^prov$', views.prov), # 获取所有省级地区的信息
        url(r'^city(d+)$', views.city), # 获取省下面的市的信息
        url(r'^dis(d+)$', views.city), # 获取市下面的县的信息
  • 相关阅读:
    python爬虫实战(八)--------知乎
    python爬虫实战(七)--------伯乐在线文章(模版)
    python分布式爬虫打造搜索引擎--------scrapy实现
    VS2010与SVN
    ASP.net 自定义控件GridView
    Asp.net Ajax提供PageMethods调用
    JSON串行化
    JOSN反串行化
    WebRequestManager对象的使用
    WebRequest调用
  • 原文地址:https://www.cnblogs.com/yifengs/p/11547287.html
Copyright © 2011-2022 走看看