天天看点

Django世界-迈出第一步-安装和创建Django

Dajngo学习

  • Django
    • 安装Django
    • 创建Django项目
      • 无创建虚拟环境的情况下
      • 有创建虚拟环境的情况下
    • Django文件含义
    • Django连接数据库并创建表的操作步骤
      • Dajngo 数据事务性
      • Dajngo 创建数据表
      • Dajngo 数据表外键
        • Dajngo 数据表保存外键
      • Dajngo 数据表删除外键
      • Dajngo 数据时间字段
        • Django 时间校验
        • Django 转换时间
      • Dajngo ORM(Objects Relational Mapping)
    • 创建 Dajngo 超级管理员
    • 总结

Django

Django是一个开放源代码的Web应用框架,由Python写成。采用了MTV的框架模式,即模型M,视图V和模版T。

安装Django

  1. 下载好Django 的安装包:

    Django-2.2.7.tar.gz

  2. 解压安装包:

    tar -zxvf Django-2.2.7.tar.gz

  3. 进入安装包:

    cd Djang-2.2.7

  4. 安装Django:

    sudo python setup.py install

  5. 查看Django版本:

    django-admin.py -- version

创建Django项目

无创建虚拟环境的情况下

  1. 找到想安装的文件下:

    django-admin startproject mydjango

  2. 进入Django项目下:

    cd mydjango

  3. 创建app:

    python manage.py startapp django

  4. 运行项目:

    python manage.py runserver 0.0.0.0:8000

安装出现的问题:

Are you sure it installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

解决办法

python -m pip install Django

有创建虚拟环境的情况下

  1. 创建文件夹 :

    mkdir wgt

  2. 进入文件夹:

    cd wgt

  3. wgt 创建虚拟环境 venv:

    python3 -m venv venv

  4. 启动虚拟环境:

    source wgt/venv/bin/activate

  5. 虚拟环境下安装Django:

    pip install django

  6. 退出虚拟机 :

    deactivate

Django文件含义

  1. settings.py : Django 如何与你的系统交互以及如何管理项目,修改一些设置,或者添加一些配置,中间键。
  2. urls.py: 告诉Django应该创建哪些页面来响应浏览请求
  3. wsgi.py : 帮助Django提供他创建的文件(web server gateway interface)
  4. init.py : 配置数据库导入包

Django连接数据库并创建表的操作步骤

  1. settings文件的DATABASES中配置数据库
  2. makemgirations创建数据库变更文件

    python manage.py makemigrations

    + 文件名
  3. migrate将变更文件应用到数据库中

    python manage.py migrate

    + 文件名
  4. 创建app,并将app添加到settings中的INSTALLED_APPS中
  5. 在app的models文件中创建数据模型
  6. makegirations创建数据库变更文件
  7. migrate将变更文件应用到数据库注意:

    只要对数据模型做了更改或者添加了新的数据模型,

  8. 数据库介绍:Django项目默认 sqlite3 数据库, 生成的数据库名为 db.sqlite3

    sqlite3 仅供测试使用,可以通过配置修改为使用 mysql

  9. 手动创建创建数据库 :

    create database db_django charest=utf-8

  10. 初始化mysql 驱动 :

    import pymysql , pymysql.install_as_MySQLdb()

setting.py 配置数据库:

DATABASES = {
	    # 配置使用mysql
	        DATABASES = {
	        'default': {
	            'ENGINE': 'django.db.backends.mysql',  # 数据库产品
	            'NAME': 'db_Django', # 数据库名
	            'HOST': 'localhost', # 主机地址,本机使用localhost,生产环境为实际主机ip
	            'PORT': '3306',  # 端口
	            'USER': 'root',  # 用户名
	            'PASSWORD': 'root',  # 密码
	        }
}
           

Dajngo 数据事务性

数据库结构的特点

  1. 数据结构化 数据之间具有联系,面向整个系统。
  2. 数据的共享性高,冗余度低,易扩充
  3. 数据独立性高
  4. 数据由DBMS统一管理和控制

数据库的事务性

字段 含义
Atomic(原子性) 指整个数据库事务是不可分割的工作单位。只有使据库中所有的操作执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。
Consistency(一致性) 指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对银行转帐事务,不管事务成功还是失败,应该保证事务结束后ACCOUNTS表中Tom和Jack的存款总额为2000元。
Isolation(隔离性) 指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
Durability(持久性) 指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

事务性

在保存订单数据中,涉及到多张表(OrderInfo、OrderGoods、SKU)的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败。

Django中对于数据库的事务,默认每执行一句数据库操作,便会自动提交。我们需要在保存订单中自己控制数据库事务的

执行流程。

在Django中可以通过django.db.transaction模块提供的atomic来定义一个事务,atomic提供两种用法

from django.db import transaction

    @transaction.atomic
    def viewfunc(request):
    # 这些代码会在一个事务中执行
        …
           
with语句用法是:

from django.db import transaction
from rest_framework.views import APIView
class OrderAPIView(APIView):
    def post(self,request):
        ....
        with transation.atomic():
            # 设置事务回滚的标记点
            sid = transation.savepoint()

            ....
            # 出现异常时 回滚事物
            try:
                ....
            except:
                transation.savepoint_rallback(sid)


            transaction.savepoint_commit(save_id)
           
在Django中,还提供了保存点的支持,可以在事务中创建保存点来记录数据的特定状态,数据库出现错误时,可以恢复到数据保存点的状态
from django.db import transaction
//创建保存点
save_id = transaction.savepoint()

//回滚到保存点
transaction.savepoint_rollback(save_id)

//提交从保存点到当前状态的所有数据库事务操作
transaction.savepoint_commit(save_id)
           

Dajngo 创建数据表

class user(models.MOdel):
      name = models.CharField(max_length=128, unique=True) //必填,最长不超过128个字符,并且唯一,也就是不能有相同姓名;
      password = models.CharField(max_length=256)//必填,最长不超过256个字符(实际可能不需要这么长);
      email = models.EmailField(unique=True) //使用Django内置的邮箱类型,并且唯一;
      sex = models.CharField(max_length=32, choices=gender, default="男") // 性别,使用了一个choice,只能选择男或者女,默认为男;
      c_time = models.DateTimeField(auto_now_add=True)

      def __str__(self):
          return self.name // 使用__str__方法帮助人性化显示对象信息;

      class Meta: //数据里定义用户按创建时间的反序排列,也就是最近的最先显示;
          db_table = 'user' // 命名数据库名字是: user
          ordering = ["-c_time"]  // 以 创建时间从大到小排序
          verbose_name = "用户"
          verbose_name_plural = "用户"
           

Dajngo 数据表外键

关于ForeignKey.on_delete的几个选项;

当一个model对象的ForeignKey关联的对象被删除时,默认情况下此对象也会一起被级联删除的。

字段 含义
CASCADE 默认值,model对象会和ForeignKey关联对象一起被删除
SET_NULL 将model对象的ForeignKey字段设为null。当然需要将null设为True
SET_DEFAULT 将model对象的ForeignKey字段设为默认值。
Protect 删除ForeignKey关联对象时会生成一个ProtectedError,这样ForeignKey关联对象就不会被删除了
字段 含义
models.CASCADE 默认为models.CASCADE 级联删除。当删除’一’时,‘多’会被删除。
modles.PROTECT 当删除一个具有外键关系的对象时,会引发一个异常,阻止删除该对象
models.SET_NULL 设置删除对象所关联的外键字段为null。但字段的null属性必需为True
models.SET_DEFAULT 设置删除对象所关联的外键字段为默认的值。
models.SET(value) 设置删除对象所关联的对象的外键字段为value,value也可以是一个可调用函数

Dajngo 数据表保存外键

何时使用save(commit=False)方法

Stackoverflow上其实已经有了一段非常精炼的答案。英文原文如下,我把它翻译了一下:

That is useful when you get most of your model data from a form, but need to populate some null=False fields with non-form data.

Saving with commit=False gets you a model object, then you can add your extra data and save it.

当你通过表单获取你的模型数据,但是需要给模型里null=False字段添加一些非表单的数据,该方法会非常有用。如果你指定commit=False,

那么save方法不会理解将表单数据存储到数据库,而是给你返回一个当前对象。这时你可以添加表单以外的额外数据,再一起存储。

何时使用save_m2m方法及如何使用

save_m2m方法只用来存储多对多的关系。当你同时满足下面两个条件时,你需要使用此方法。如果你直接使用save()或form_valid()方法,是可以直接存储多对多(m2m)关系的,不需要用save_m2m。

你使用了save(commit=False)方法

你的model里有多对多的关系(比如tags)

if user_create_form.is_valid():
            new_user = user_create_form.save(commit=False)
            new_user.password = make_password(user_create_form.cleaned_data['password'])
            if 'file' in request.FILES:
                file_name = 'media/image/' + request.POST.get('name') + '_' + str(int(time.time())) + '.' + \
                            file_obj.name.split('.')[
                                -1]  # 构造文件名以及文件路径
                print(file_name)
                with open(file_name, 'wb+') as f:
                    print(file_obj.read())
                    f.write(file_obj.read())
                new_user.image = file_name[6:]
            new_user.save()
            user_create_form.save_m2m()

            ret = {'status': 'success'}
           

Dajngo 数据表删除外键

记录一下踩的坑,同一个数据库下两个表,举个例子 user_info 表中的 username字段设置为外键,关联了 表user_pwd中的主键字段 

user,现在因为重建表结构等原因,要把这个外键删除,这里的删除语法为:

alter table 表名 drop foreign key 外键别名;
           

需要注意的是,外键别名并不是设置为外键的字段名,

假如我们直接 alter table user_info drop foreign key username;这时候会报语法错误!

我们要在命令行输入 

show create table user_info

;这时候会显示建表的信息,有这么一句话
这时候我们要这么修改

alter table user_info drop foreign key user_info;

这个时候就删除了表中字段的外键约束,这时候我们再 

alter table user_info drop username

,就可以删除这个原本是外键的字段了!

Dajngo 数据时间字段

字段 含义
DateTimeField 日期+时间,与python里的 datetime.datetime 实例同,数据库字段内容为 2018-08-30 16:31:00
DateField 日期,与python里的 datetime.date 实例同。数据库字段内容为 2018-08-30,datetime.date 传到前台的值会转换成 2019年12月5日

有以下两个可选的选项,均为bool类型:

参数1:auto_now,默认值为false,设置为true时,每次执行 save 操作时,将其值设置为当前时间,并且每次修改model,都会自动更新。

使用场景:这个参数在需要存储“最后修改时间”的场景下,十分方便。

注意:设置该参数为true时,并不意味着字段的默认值设为当前时间,而是指字段会被“强制”更新到当前时间,你无法程序中手动为字段赋值;如果使用django自带的admin管理器,那么该字段在admin中是只读的。

参数2:auto_now_add,默认值为false,设置为true时,会在model对象第一次被创建时,将字段的值设置为创建时的时间,以后修改对象时,字段的值不会再更新。

使用场景:该属性通常被用在存储“创建时间”的场景下。

注意:一旦被设置为True,就无法在程序中手动为字段赋值,在admin中字段也会成为只读的。

auto_now和auto_now_add被设置为True后,这样做会导致字段成为editable=False和blank=True的状态。editable=False将导致字段不会被呈现在admin中,blank=Ture表示允许在表单中不输入值。

Django 时间校验

//转换成规范的时间
print(datetime.datetime.strptime(date_text, '%Y-%m-%d 00:00:00'))
           
//判断是否是时间格式
def validate(date_text):
    try:
        datetime.datetime.strptime(date_text, '%Y-%m-%d 00:00:00')
        flag = True
    except ValueError:
        flag = False
    return flag
           

Django 转换时间

//下载数据时,将不规范的时间转换
# cls=DateEnconding 转换成 2019/12/9
  result = json.dumps(data, cls=DateEnconding)

  class DateEnconding(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime.date):
            return o.strftime('%Y/%m/%d')

           

安装出现的问题:

init() missing 1 required positional argument: ‘on_delete’

解决办法

category = models.ForeignKey(Category, verbose_name=‘分类’, on_delete=models.CASCADE)

在末尾加上 on_delete=models.CASCADE

安装Pymysql的问题:

django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None

解决办法

找到Python安装路劲下的Python36-32\Lib\site-packages\django\db\backends\mysql\base.py文件将文件中的如下代码注释

if version < (1, 3, 3):

raise ImproperlyConfigured(“mysqlclient 1.3.3 or newer is required; you have %s” % Database.version)

重新在项目manage.py路劲下执行如下命令即可

安装数据库出现的问题:

No changes detected

解决办法

第一步:

删除该app下的migrations下的所有文件。

第二步:

进入数据库,将对应的该app所有相关表删除

第三步:执行一下三条命令

blog>python manage.py makemigrations --empty myblog

blog>python manage.py makemigrations

blog>python manage.py migrate

或者

python manage.py migrate --fake

Dajngo ORM(Objects Relational Mapping)

** 对象关系映射,是一种程序技术,用于实现对象编程语言里不同类型系统的数据之间的转换,ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。**

ORM将对对象的操作转换为原生SQL

优点

易用性,可以有效减少重复SQL

性能损耗少

设计灵活,可以轻松实现复杂查询

移植性好

  1. 模型查询
    1. 模型成员objects
      Django默认通过模型的objects对象实现数据查询
                 
    2. 过滤器
      Django有两种过滤器用于筛选记录
                 
      filter    : 返回符合筛选条件的数据集
      exclude   : 返回不符合筛选条件的数据集
                 
      1. all() 返回所有数据

        filter() 返回符合条件的数据

        filter(条件1,条件2,条件3)

        filter(条件1).filter(条件2).filter(条件3)

        exclude() 查询不满足条件的数据

      1. order_by() 排序

        升序:模型名.objects.all().order_by(‘id’)

        降序:模型名.objects.all().order_by(’-id’)

      1. 运算符

        icontains:大小写不敏感

        contains:大小写敏感

        模型名.objects.filter(s_name__icontains=‘小’)

        startswith:以什么开始

        endswith:以什么结束

      1. 范围查询

        gt gte:大于、大于等于 —>greater than greater than equal

        lt lte:小于、小于等于

        in:在范围之内

      1. values 获取

        values方法可以获取number字段的字典列表。

        values_list可以获取number的元组列表。

        values_list方法加个参数flat=True可以获取number的值列表。

      1. 查询单个数据

        get():返回一个满足条件的对象

        获取不到数据会报错

        get只能返回一个对象,如果找到多个会引发模型类MultiObjectsReturned异常

        get_or_create():获取不到对象就创建对象

        get_or_update();获取到对象就修改对象

      1. 查询先后条件

        first():返回查询集中的第一个对象

        last():返回查询集中的最后一个对象

        count():返回当前查询集中的对象个数

        exists():判断查询集中是否有数据,如果有数据返回True,没有返回False

      1. 查询或者条件/不等于条件

        并且:filter(条件1,条件2,条件3)

        或者:filter(Q(条件1) |Q(条件2))

        取反:filter(~Q(条件1) | Q(条件2))

      1. A字段和B字段进行算数运算

        F()

        filter(shuxue__gt = F(‘yuwen’) + 10)

例子:

大于等于2 的书籍 且不等于3 的书籍

[<Book: 西游记>, <Book: 水浒传>]
           
book = list(Book.objects.filter(id__gte=2).filter(~Q(id=3))) 
    book = list(Book.objects.filter(id__gte=2).exclude(id=3).values())
           

外键查询

三国演义/黑龙江科技大学
西游记/西安工业大学
红楼梦/黑龙江科技
水浒传/黑龙江
           

根据外键 查询外键表,重新命名为‘publish_name’

books = Book.objects.annotate(publish_name=F('publish__name'))
for book in books:
      print('%s/%s' % (book.title, book.publish_name))
           
books = Book.objects.all()
 # <QuerySet [{'publish__name': '黑龙江科技大学', 'title': '三国演义'}]>
for book in books:
      print('%s/%s' % (book.title, book.publish.name))
           
books = Book.objects.filter().values('publish__name', 'title')
#<QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 红楼梦>, <Book: 水浒传>]>
for book in books:
      print('%s/%s' % (book['title'], book['publish__name']))
           

总结:

  1. 第一种直接就把外键的name查询出,无需重新查询
  2. 第二种 需要查询
<QuerySet [{'id': 1, 'title': '三国演义', 'price': 100, 'pub_date': datetime.date(2019, 1, 8), 'publish_id': 1, 'publish_name': '黑龙江科技大学'}]>
<QuerySet [{'id': 1, 'title': '三国演义', 'price': 100, 'pub_date': datetime.date(2019, 1, 8), 'publish_id': 1}]>
           
  1. 排序 order_by
books = Book.objects.order_by('create_time')
class Meta:
  orderinf = ['create_time','price']
           

创建 Dajngo 超级管理员

首选创建一个新用户,用来登录Django管理网站,进入manage.py目录下,使用如下命令来进行创建:

python manage.py createsuperuser

接下来输入用户名称:

Username(leave bkank to use ‘administrator’): root

然后是输入邮箱(QQemail等都可以):

Email address:(输入你的邮箱账号)

输入密码(输入密码时不会显示出来,并且长度必须超过八位才行):

Password:********

Password(again):********

当两次密码输入相同且超过八位的时候,就会提示创建超级用户成功:

Superuser created successfully.

再次运行你的服务,输入账号和密码就可以成功登陆了:

python manage.py runserver

总结

关于django框架

  1. 首先,django在运行程序时,最开始当你输入正确的网络地址的时候,

    django会进入路由模块(urls)中去寻找是否有符合其要求的路径,

    auth后面跟的就是路由路径了。我们在页面地址栏中输入“localhost:8000/index/”,

    django会自动的寻找路由表(urls)中符合要求的后缀为“index/”的路径。

    找到后,如果有index/,将会去执行这个路由后面所指向的函数。而这个函数就是view中的函数,执行函数相应的响应过程以后,

  2. 必定会return返回并跳转相应页面及携带数据。

    (django强制要求必须return返回,强制返回主要原因是每一次网页操作,都会相应的跳转页面或交互)

    看到return语句后面是不是跟着“index.html”,这就是让程序自动自行index的页面。

    那么来到templates文件夹中打开这个页面。恭喜你,打开index.html页面。

  3. 经过上面的步骤,

    可以看出,我们程序的执行流程是:路由,视图调度(V层),前端页面(HTML)。

    所以我们在开发中,为了让大脑清晰,方便执行,我们从最容易观察到的前端页面视图层开始开发,这样不断能够及时的看到很好的反馈,

    若看不到页面,我们还能及时的找到问题出在什么地方,能够及时的做出调整。