我的Blog搭建之旅2——Django与数据库

我的Blog搭建之旅2——Django与数据库

=== 2019.2.1 ===

写完一点代码回来再看

MVC & MTV

  • MVC:Models、Views and Controler

    • Models负责与数据库交流,将必要的信息保存到数据库中
    • Views负责网页前端的展示
    • Controler负责根据用户的操作访问“模型”,然后返回相应的“视图”给用户,是联系Views和Models的纽带

    2012032011584641

  • MTV:Django的模式 ,Models,Views & Templates

    • Models跟上面的功能相同,用来与数据库交流
    • Templates储存模版,就是前端的html文件
    • Views负责接收用户的请求,访问Models,并填充Templates返回给用户
  • 两者的不同:

    • 感觉上像是Django将MVC中的视图进一步分解为 Django视图 和 Django模板两个部分,分别决定 “展现哪些数据” 和 “如何展现”,使得Django的模板可以根据需要随时替换,而不仅仅限制于内置的模板。
    • 至于MVC控制器部分,由Django框架的URLconf来实现

模型 (Models)

< 模型与数据库 >
  • 每一个模型都映射一个数据库表,保存在数据库中;同时每一个模型都是一个python的类,继承自django.db.models.Model。所以,每一个都作为一个table保存在数据库中,每一个类的成员都作为属性 保存在table中。

    我的一个model的定义:

    class Question(models.Model):
        # CharField 需要一个 max_length 参数。这个参数的用处不止于用来定义数据库结构,也用于验证数据
        question_text = models.CharField(max_length=200)
    
        pub_date = models.DateTimeField('date published')
    
        # __str__ 方法的作用是美化打印出来的结果,就是print的时候不会返回一个类似于"<__main__.Test object at 0x1387B8>"的东西
        def __str__(self):
            return self.question_text
    
        def was_published_recently(self):
            # 如果问题创建的时间在现在的时间减去一天之后,就算最近创建(有bug)
            # return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
            # 问题创建的时间需要满足(一天之前,现在)
            now = timezone.now()
            return now - datetime.timedelta(days=1) <= self.pub_date <= now
    

    运行migrate的时候会按照如下语法创建一个表:

    CREATE TABLE blogpost_question (
        "id" serial NOT NULL PRIMARY KEY,
        "question_text" varchar(200) NOT NULL,
        "pub_data" datetime NOT NULL
    );
    # 表的名字一般是“应用名”_“类名”
    

    同时我有这个类的一个实例,所以,在数据库中:

    mysql> select * from blogpost_question; # 这就是放这个model的一个table的名字
    +----+---------------+----------------------------+
    | id | question_text | pub_date                   |
    +----+---------------+----------------------------+
    |  1 | What's up?    | 2019-01-30 13:05:38.320765 |
    +----+---------------+----------------------------+
    1 row in set (0.03 sec)
    
    

    在后台管理页面中:

    image-20190201095941815

< makemigration & migrate >
  • 先提纲挈领的说,makemigration是将models.py中的改动记录到migrations.py中,但是不更新数据库;migrate是迁移,将Model的改动保存到数据库中。所以我们修改Model的时候需要先makemigration保存修改,然后再migrate执行修改。
< 字段 >
  • 字段指每个类的成员的“类型”,对应于数据库中的属性的类型,常用的字段有如下几种:

    • CharField:字符串字段,有一个额外的必需参数: maxlength ,它是字段的最大长度(字符数)
    • DateFieldDateTimeField:日期字段、日期时间字段
    • FloatField :浮点数,必须参数
      • max_digits :数字中允许的最大的数字位数
      • decimal_places :数字的小数位数
    • IntegerField: 整数
    • TextField :不限长度的文字长度
    • BinaryField:bool类型
  • 也可以自定义字段类型,更详细的字段参考 https://docs.djangoproject.com/en/2.1/ref/models/fields/

  • 用于所有字段的可选选项

    • null:默认值设置为NULL,默认为False

    • blank:是否允许为空,默认False

    • choices:可选的值,使用方法如下:

      class Person(models.Model):
          SHIRT_SIZES = (
              ('S', 'Small'),
              ('M', 'Medium'),
              ('L', 'Large'),
          )
          name = models.CharField(max_length=60)
          shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
      

      每个二元组的第一个值会储存在数据库中,而第二个值将只会用于显示作用。对于一个模型实例,要获取该字段二元组中相对应的第二个值,使用 get_FOO_display() 方法。

    • default:默认值

    • primary_key:是否为主键,如果没有的话会自动设置主键

    • unique:数据库类似功能

  • ……后面的暂时没看

< 模型的方法 >
  • 就是给自己的模型定义一个函数吧。。。因为没有学过python的类所以不是特别的理解
  • __str__( )方法就是在需要显示为纯字符的时候使用的情况,前面在显示后台字段的时候使用过。
< 关联关系 >
  • Many-to-many:多对多

    • eg:一个学生可以选很多节课,一门课也可以有很多学生来选。
    • 字段为models.ManyToManyField
  • Many-to-one:就是普通的Foreign Key约束

    • eg:比如 学生所在的班级 ==> 班级的序号,多个学生可以在一个班级,班级的序号就是学生的一个外键。

    • 字段就设置为models.ForeignKey类,比如之前的例子就是这样子的:

      class Choice(models.Model):
      	question = models.ForeignKey(
              Question, 
              on_delete=models.CASCADE
          )
      
  • One-to-one:一对一

    • 字段为OneToOneField

模型的API

我们使用的示例模型如下:

class BabyInfo(models.Model):
    name = models.CharField(max_length=30)
    sex = models.BinaryField()
    age = models.IntegerField()

    def __str__(self):
        return self.name
< 基本操作>

感觉好像所有的过程都是在shell中进行的诶。。

  • 查:
#这里取出来了babyinfo表中的所有列,数据类型为QuerySet,更详细的讲解见下
babys = models.BabyInfo.objects.all()
# select操作使用get与filter
baby1 = babys.get(pk=1)
# 投影操作使用values
babynames = babys.values('name')
  • 填:

    #调用创建函数
    models.BabyInfo.objects.create(name='zyz',sex=0,age=21)
    #或者直接实例话
    models.BabyInfo(name='zyz',sex=0,age=21)
    #如果太长的话可以这样子
    baby1 = {'name':'zyz','sex':0,'age':12}
    model.BabyInfo.objects.create(**baby1)
    #当你创建完之后必须save才可以执行插入操作 INSERT INTO
    baby1.save()
    
  • 删:

    # 使用delete()方法删除
    >>> babyzyz = babys.filter(name='zyz')
    >>> babyzyz
    <QuerySet [<BabyInfo: zyz man 12>, <BabyInfo: zyz 男 12>]>
    >>> babyzyz.delete()
    (2, {'server.BabyInfo': 2})
    >>> babyzyz
    <QuerySet []>
    # 需要注意的是,即使你在提取出来的对象上删除,也会直接进行数据库上的操作,删除需谨慎!!
    # 如果你要删除全部的话,必须使用QuerySet而不是Manager,这是为了防止误删
    >>> BabyInfo.objects.delete()
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: 'Manager' object has no attribute 'delete'
    >>> BabyInfo.objects.all().delete()
    (6, {'server.BabyInfo': 6})
    
  • 改:

    # 使用update方法
    >>> babys
    <QuerySet [<BabyInfo: zyz 男 12>]>
    # 直接赋值是没有用的
    >>> babys[0].age = 21
    >>> babys
    <QuerySet [<BabyInfo: zyz 男 12>]>
    # 必须对QuerySet对象进行操作而不是BabyInfo对象
    >>> babys[0].update(age = 21)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: 'BabyInfo' object has no attribute 'update'
    # get返回的是实际对象而不是QuerySet
    >>> babys.get(pk=1).update(age = 21)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: 'BabyInfo' object has no attribute 'update'
    # filter返回QuerySet
    >>> babys.filter(pk=1).update(age = 21)
    1
    >>> babys
    <QuerySet [<BabyInfo: zyz 男 21>]>
    # 赋值对一个实际对象是有用的,要记得save
    >>> baby1 = babys.get(pk=1)
    >>> baby1.age = 12
    >>> baby1.save()
    >>> babys
    <QuerySet [<BabyInfo: zyz 男 12>]>
    
    

============= 下班啦,下午不来上班了有空就接着写吧 ==============

< 模型流程 >
  1. 在models.py中创建一个model(就是一个类)
  2. 在admin.py中注册方便后台管理页面管理,这样可以在admin/界面查看
  3. 执行makemigrations和migrate同步数据库
< 中文支持问题 >

在增加数据的时候遇到了这样一个问题:

django.db.utils.OperationalError: (1366, "Incorrect string value: '\\xE9\\x9A\\xBE' for column 'sex' at row 1")

这个表明数据的编码不是utf-8,我们需要进入数据库加入这么一句就可以解决了

alter table Blog.server_babyinfo convert to character set utf8

可是每次创建表格都要修改的话十分麻烦,目前还没有找到创建数据库的时候就修改编码方式的办法

数据库查询

< QuerySet & Manager >
  • 基本方法
    • filter,exclude
    • 连续过滤
    • get方法
    • 索引与切片(毕竟是python)
# 首先我们获取一个QuerySet
>>> from server.models import BabyInfo
>>> babys = BabyInfo.objects.all()
# select操作
>>> babys.filter(age=12)
<QuerySet [<BabyInfo: zyz man 12>, <BabyInfo: zyz 男 12>, <BabyInfo: 张云哲 男 12>, <BabyInw 男 12>, <BabyInfo: 1212>]>
# 反选
>>> babys.exclude(age=12)
<QuerySet [<BabyInfo: 张云哲 男 21>, <BabyInfo: 啦啦 男 1>, <BabyInfo: www 男 23>]>
# 可以连续过滤,因为filter总是返回一个QuerySet对象;如果不存在就返回空对象
>>> babys.exclude(age=12).filter(name='张云哲')
<QuerySet [<BabyInfo: 张云哲 男 21>]>
>>> babys.exclude(age=12).filter(name='zyz')
<QuerySet []>
# 如果你只想找一个对象而不是一个QuerySet,那你直接使用get方法就可以了
>>> baby1 = babys.get(pk=1)
>>> baby1
<BabyInfo: zyz man 12>
>>> type(baby1)
<class 'server.models.BabyInfo'>
# 但有0个或多个对象符合条件,就会直接报错;所以尽量用主键查找
>>> babys.get(name='baibai')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/anaconda3/envs/Blog/lib/python3.6/site-packages/django/db/models/query.py", line 403, in get
    self.model._meta.object_name
server.models.DoesNotExist: BabyInfo matching query does not exist.
>>> babys.get(name='zyz')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/anaconda3/envs/Blog/lib/python3.6/site-packages/django/db/models/query.py", line 407, in get
    (self.model._meta.object_name, num)
server.models.MultipleObjectsReturned: get() returned more than one BabyInfo -- it returned 2!
# QuerySet对象支持索引和切片
>>> babys[0]
<BabyInfo: zyz man 12>
>>> babys[:3]
<QuerySet [<BabyInfo: zyz man 12>, <BabyInfo: 张云哲 男 21>, <BabyInfo: zyz 男 12>]>
>>> babys[1:5:2]
[<BabyInfo: 张云哲 男 21>, <BabyInfo: 张云哲 男 12>]
< 字段查找 >
  • filter、get的参数当然不仅限于相等,我们可以使用python的函数机制来进行类似于Mysql中的WHERE运算,基本查找关键字参数采用格式field__lookuptype=value,注意这里是下划线
Python能够定义接受任意名称 - 值参数的函数,这些参数的名称和值在运行时进行计算。有关更多信息,请参阅官方Python教程中的关键字参数。
  • 常用的lookuptype:

    名称作用注释
    exact准确的等于,等价于 =等价于SQL语句:SELECT … WHERE filed = …
    更准确的来说,普通的=语句就暗示了使用exact
    iexact不区分大小写的等于以后所有的type加上前缀i都是不区分大小写,不再区分
    contains包含关系等价于SQL:SELECT … WHERE filed LIKE ‘%…%’;
    startwith,
    endwiths
    以……开头/结尾
    gt/lt/gte/lte大于/小于/大于等于/小于等于gt:greater than
    lt:less than
    e:equa
    date/year/month针对Date格式
    isnull为空
    regex正则表达式使用例子:
    Entry.objects.get(title__regex=r’^(An?

== 2019.2.18 ==

RestFramework

  • RestFramework是做什么的?

    RestFramework是一个能快速为我们提供API接口,方便我们编程的框架。API是后端编程人员写的,为了让前端拿数据的一个接口,通常就是以url的形式存

< REST >

这个博客写的很有意思:https://zhuanlan.zhihu.com/p/30396391?group_id=937244108725641216

简单来说,REST就是将你本来看完可能不太知道是干啥的url转换为你一下就能看清楚的url:“URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。”

混乱的url										REST风格
GET /rest/api/getDogs 				--> 	GET /rest/api/dogs 获取所有小狗狗 
GET /rest/api/addDogs 				--> 	POST /rest/api/dogs 添加一个小狗狗 
GET /rest/api/editDogs/:dog_id 		--> 	PUT /rest/api/dogs/:dog_id 修改一个小狗狗 
GET /rest/api/deleteDogs/:dog_id 	--> 	DELETE /rest/api/dogs/:dog_id 删除一个小狗狗
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较大的问题,我会尽可能地简要地回答。首先,对于需求分析,你需要考虑以下几个方面: 1. 博客的功能要求:包括博客的基本功能(如发布文章、编辑文章、删除文章等)、用户权限管理、评论管理、搜索功能等。 2. 博客的设计要求:包括博客的整体设计(如主题、样式、排版等)、文章的分类、标签等。 3. 数据库的设计:包括数据库的表设计、数据表之间的关系、索引设计等。 对于数据库的设计,你可以考虑使用 Django 自带的 ORM(Object-Relational Mapping)框架,它可以帮助你更方便地操作数据库。 以下是一个简单的数据库表设计示例: ```python from django.db import models class Category(models.Model): name = models.CharField(max_length=100) class Tag(models.Model): name = models.CharField(max_length=100) class Post(models.Model): title = models.CharField(max_length=100) body = models.TextField() created_time = models.DateTimeField(auto_now_add=True) modified_time = models.DateTimeField(auto_now=True) excerpt = models.CharField(max_length=200, blank=True) category = models.ForeignKey(Category) tags = models.ManyToManyField(Tag, blank=True) ``` 在这个示例中,我们定义了三个数据表:Category、Tag 和 Post。Category 表和 Tag 表分别用于存储文章的分类和标签,Post 表用于存储文章的内容。其中,Post 表和 Category 表之间是一对多的关系,Post 表和 Tag 表之间是多对多的关系。 当你定义完数据表之后,可以使用 Django 的命令行工具来生成数据库表格: ``` python manage.py makemigrations python manage.py migrate ``` 这样,你就可以开始在 Django 中使用这些数据表了。 当然,这只是一个简单的示例,实际的博客系统可能会更复杂,你需要根据自己的需求进行设计。希望这些信息对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值