模型和数据库

当你想到数据库时,你通常会想到结构化查询语言(SQL),这是我们查询数据库得到我们需要的数据的常用方法。在Django中,查询底层数据库(可以存储各种数据,比如您网站的用户信息)由对象关系映射器(ORM)负责处理。实质上,存储在数据库表中的数据可以被封装在一个模型。 模型是描述数据库表数据的Python对象。 而不是通过SQL直接在数据库上工作,你只需要操纵对应的Python模型对象。

本章将向您介绍使用Django进行数据管理的基础知识及其ORM。你会发现在你的应用程序底层数据库中添加,修改和删除数据是非常容易的。并且
从数据库获取数据到用户的Web浏览器有多简单。

5.1 Rango的要求

在开始之前,让我们回顾一下我们正在开发的Rango应用程序的数据要求。
应用程序的全部需求在前面详细介绍,但为了让您更好记忆,我们快速总结一下客户的需求。

  • Rango本质上是一个网页目录- 包含指向其他网站的链接的网站。
  • 有许多不同的网页类别,每个类别的收纳一些链接。我们在概述章节中假设这是一个一对多的关系。 查看该下面的实体关系图。
  • 一个类别有名字,访问次数和喜欢数。
  • 一个页面是指一个类别,有标题,网址和浏览数。

5.2 告诉Django你的数据库

在我们创建任何模型之前,我们需要用Django来设置我们的数据库。 在Django 1.11中,当你建立一个新的项目,变量DATABASES是在你自动创建的settings.py模块中。 它会看起来类似于下面的例子:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

5.3 创建模型

settings.py中配置好数据库后,让我们为Rango应用创建两个初始数据模型。 Django应用程序的模型存储在相应的models.py模块。 这意味着对于Rango,模型被存储在内部rango/models.py

定义类别和页面模型如下。

class Category(models.Model):
    name = models.CharField(max_length=128, unique=True)
    def __str__(self):# For Python 2, use __unicode__ too
        return self.name

class Page(models.Model):

    category=models.ForeignKey(Category)
    title=models.CharField(max_length=128)
    url=models.URLField()
    views=models.IntegerField(default=0)

    def __str__(self)# For Python 2, use __unicode__ too
        return self.title

定义模型时,需要指定字段及其关联类型的列表以及任何必需或可选参数。默认情况下,所有模型都有一个自动增加的整数x字段,称为id,它被自动分配并作为主键。

Django提供了一系列全面的内置字段类型。 一些最常用的详细如下

  • CharField,用于存储字符数据(例如,字符串)的字段。指定
    最长长度,提供一个字段可以存储的最大字符数。
  • URLField,很像CharField,但专为存储资源URL而设计。 你也可以
    指定一个最长长度参数。
  • IntegerField,存储整数。
  • DateField,它存储一个Python datetime.date对象

对于每个字段,您可以指定唯一属性。如果设置为True,则整个数据库模型中只能存在该字段中特定值的一个实例。 例如,看看我们的类别上面定义的模型。字段名称已被设置为唯一 - 因此每个类别名称必须是唯一的。 这意味着您可以像使用主键一样使用该字段。您也可以为每个字段指定其他属性,例如使用语法default ='value'指定默认值,以及字段的值是否为空(或NULL)(null = True)或不是(null = False)。

Django为数据库中的相关模型提供了三种机制,它们是:

  • ForeignKey,一种允许我们创建一对多关系的字段类型
  • OneToOneField,一种允许我们定义严格的一对一关系的字段类型
  • ManyToManyField,允许我们定义多对多关系的字段类型

5.4 创建和迁移数据库

通过在models.py中定义的模型,我们现在可以让Django发挥其魔力,并在底层数据库中创建表。 Django提供了所谓的迁移工具,帮助我们设置和更新数据库,以反映对模型的任何更改。 例如,如果要添加新字段,则可以使用迁移工具来更新数据库。

配置

首先,数据库必须被初始化。 这意味着创建它和其中的所有关联表,以便数据可以存储在其中。 要做到这一点,你必须打开终端或命令提示符,并导航到你的项目的根目录 - manage.py的存储位置。 运行以下命令。

python manage.py migrate

Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

接下来,创建一个超级用户来管理数据库。 运行以下命令。

C:\Users\XC\PycharmProjects\tango_with_django_project>python manage.py createsuperuser
Username (leave blank to use 'xc'): xc
Email address: XXXXXX@qq.com
Password:
Password (again):
Superuser created successfully.

创建和更新模型/表格

每当你改变你的应用程序的模型,你需要通过manage.py中的makemigrations命令注册更改

$ python manage.py makemigrations rango
Migrations for 'rango':
rango\migrations\0001_initial.py
- Create model Category
- Create model Page

在为应用程序创建迁移之后,您需要将它们提交到数据库。

$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, rango, sessions
Running migrations:
Applying rango.0001_initial... OK

5.5 Django模型和Shell

在我们将注意力转移到演示Django管理界面之前,值得注意的是,您可以直接使用Django shell与Django模型进行交互 - 这是一个非常有用的工具,用于调试目的。 我们将演示如何使用此方法创建一个类别实例。

$ python manage.py shell
Python 3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.
IPython 5.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.

In [1]: from rango.models import Category

In [2]: print(Category.objects.all)
<bound method BaseManager.all of <django.db.models.manager.Manager object at 0x00000290DF925240>>

In [3]: print(Category.objects.all())
<QuerySet []>

In [4]: c = Category(name ='Test')

In [5]: c.save()

In [6]: print(Category.objects.all())
<QuerySet [<Category: Test>]>

In [7]: quit()

5.6 配置管理界面

$ python manage.py runserver

点击http://127.0.0.1:8000/admin/,用之前注册的用户名和密码登陆。为了在界面中包含类别和界面模块,修改rango/admin.py

from django.contrib import admin
from rango.models import  Category,Page

# Register your models here.
admin.site.register(Category)
admin.site.register(Page)

5.7 创建一个填充脚本

将测试数据输入到数据库往往是一件麻烦事。 许多开发者会通过随机点击密钥来添加一些伪造的测试数据,就像wTFzm8j3z7一样。
比起这样,最好编写一个脚本,以便你和你的合作者使用相同的测试数据。 此外,这种方法将保证你有有用的和伪现实的数据,而不是随机的垃圾。因此,为您的应用程序创建所谓的填充脚本是一个很好的做法。 此脚本旨在自动为您的数据库填充测试数据。
为了Rango创建一个填充脚本,首先你在项目的根目录下创建
populate_rango.py文件并添加下面的代码。

import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE','tango_with_django_project.settings')

import django
django.setup()
from rango.models import  Category,Page

def populate():
    # First, we will create lists of dictionaries containing the pages
    # we want to add into each category.
    # Then we will create a dictionary of dictionaries for our categories.
    # This might seem a little bit confusing, but it allows us to iterate
    # through each data structure, and add the data to our models.
    python_pages = [
        {"title":"Official Python Tutorial",
         "url":"http://docs.python.org/2/tutorial/",},
        {"title":"How to Think like a Computer Scientist",
         "url": "http://www.greenteapress.com/thinkpython/",},
        { "title": "Learn Python in 10 Minutes",
          "url": "http://www.korokithakis.net/tutorials/python/", }]

    django_pages = [
        {"title": "Official Python Tutorial",
         "url": "https://docs.djangoproject.com/en/1.9/intro/tutorial01/", },
        {"title": "Django Rocks",
         "url": "http://www.djangorocks.com/", },
        {"title": "How to Tango with Django",
         "url": "http://www.tangowithdjango.com/",}
    ]

    other_pages = [
        {"title": "Bottle",
         "url": "http://bottlepy.org/docs/dev/", },
        {"title": "Flask",
         "url": "http://flask.pocoo.org", }
    ]
    cats ={
        "Python":{ "pages":python_pages},
        "Django":{"pages":django_pages},
        "Other Frameworks":{"pages":other_pages},
    }

    # The code below goes through the cats dictionary, then adds each category,
    # and then adds all the associated pages for that category.
    # if you are using Python 2.x then use cats.iteritems() see
    # http://docs.quantifiedcode.com/python-anti-patterns/readability/
    # for more information about how to iterate over a dictionary properly.

    for cat, cat_data in cats.items():
        c = add_cat(cat)
        for p in cat_data["pages"]:
            add_page(c,p["title"],p["url"])

    #print out the categories we have added.
    for c in Category.objects.all():
        for p in Page.objects.filter(category=c):
            print("-{0}    -{1}".format(str(c),str(p)))

def add_page(cat,title,url,views = 0):
    p = Page.objects.get_or_create(category =cat,title =title)[0]
    p.url = url
    p.views = views
    p.save()
    return p


def add_cat(name):
    c = Category.objects.get_or_create(name = name)[0]
    c.save()
    return c

#Start execution here!
if __name__ == '__main__':
    print("Starting rango population script...")
    populate()

执行

python populate_rango.py

Starting rango population script...
-Python    -Official Python Tutorial
-Python    -How to Think like a Computer Scientist
-Python    -Learn Python in 10 Minutes
-Django    -Official Python Tutorial
-Django    -Django Rocks
-Django    -How to Tango with Django
-Other Frameworks    -Bottle
-Other Frameworks    -Flask

接下来,验证填充脚本实际填充数据库。 重新启动Django开发服务器,导航到管理界面(http://127.0.0.1:8000/admin/rango/page/),并检查你有一些新的类别和页面。

5.8 工作流程:模型设置

设置您的数据库

有了一个新的Django项目,你应该首先告诉Django你打算使用的数据库(即在settings.py配置DATABASES)。 你也可以在admin.py中注册任何你的应用程序模型模块,使他们可以通过管理界面访问。

添加模板

五步

  • 1 首先,在Django应用程序的 models.py文件中创建新的模型。
  • 2 更新admin.py来包含并注册您的新模型。
  • 3 执行迁移 $ python manage.py makemigrations <app_name>
  • 4 应用更改 $ python manage.py migrate。 这将为您的新模型在数据库中创建必要的基础设施。
  • 5 为你的新模型创建/编辑填充脚本。

总有一天,你将不得不删除你的数据库。 发生这种情况时,从manage.py
模块运行下面的命令.

1 . 迁移你的数据库 - 这将在新的数据库中设置一切。 确保您的应用程序在提交的迁移中列出。 如果不是,请运行makemigrations <appname>命令
2 .使用创建超级用户命令创建一个新的管理帐户。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容