Django快速入门-数据库模型详细操作教程
本系列教程第一部分已经讲完了。在上一个教程的基础上,在这一讲中我们将建立数据库,创建第一个模型,并使用一个 Django 快速自动生成的管理站点。
现在,打开mysite/settings.py。Django设置模块级的变量与正常的Python模块一样。
默认情况下,配置使用SQLite。如果你是数据库新手,或者想尝试学习Django,这是最简单的选择。SQLite包含在Python,所以不需要安装任何东西来支持你的数据库。当开始你的第一个真正的项目,可能需要使用更强大的数据库如:PostgreSQL,MySQL等,可以配置数据库切换就可以了。
如果你想使用其他数据库,请安装相应的数据库绑定,并更改以下键在数据库中“默认”的配置项,以适合您的数据库连接设置:
ENGINE – 输入'django.db.backends.sqlite3', 'django.db.backends.postgresql','django.db.backends.mysql',或'django.db.backends.oracle' NAME – 数据库的名称。如果使用SQLite,数据库会在您的计算机上创建文件;在这种情况下,名称应该是完整的绝对路径的文件,包括文件名。默认值为 os.path.join(BASE_DIR,“db.sqlite3”),将存储在您的项目目录中的文件。
如果你不使用SQLite作为数据库,而使用其他设置,如USER, PASSWORD, 和 HOST 必须加入。欲了解更多详细信息,请参阅用于 数据库的参考文档。
当你编辑 mysite/settings.py,时区设置TIME_ZONE。
此外,请注意,在该文件的顶部的 INSTALLED_APPS 设置。它包含了很多在本Django示例中激活的所有 Django 的应用程序的名称。 应用程序可以在多个项目中使用,你可以打包给别人并在他们的项目分发使用。
默认情况下,INSTALLED_APPS包含以下内容的应用程序,这些都使用 Django :
django.contrib.admin – 管理站点,这里会很快使用它 django.contrib.auth – 认证系统 django.contrib.contenttypes – 一个框架,内容类型 django.contrib.sessions – 会话框架 django.contrib.messages – 消息传递框架 django.contrib.staticfiles – 一个框架用来管理静态文件
这些应用包括默认,作为一个方便常见的实例。
其中的一些应用程序使用至少一个数据库表,所以我们需要在数据库中创建的表才可以使用它们。要做到这一点,运行以下命令:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 C:\Python27\mysite>python manage.py migrate Operations to perform: Apply all migrations: admin, contenttypes, auth, sessions Running migrations: Rendering model states... DONE 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 sessions.0001_initial... OK C:\Python27\mysite>
migrate 命令着眼于INSTALLED_APPS设置并创建根据您的 mysite/settings.py 文件数据库设置,并随应用程序数据库迁移任何数据库表(我们将在以后的教程讨论)。你会看到每个适用移植的消息。 如果有兴趣,运行命令行在你的数据库客户端,列如类型\dt (PostgreSQL), SHOW TABLES; (MySQL), .schema (SQLite), 或 SELECT TABLE_NAME FROMUSER_TABLES; (Oracle) 以显示Django所创建的表。
现在,我们将定义模型 - 本质上数据库进行设计,使用其他元数据。
在我们的简单调查的应用程序,我们将创建两个模型:Question 和 Choice。Question有一个问题标题和发布日期。Choice有两个字段:选择文本和票数。每个选项都与一个问题关联。
这些概念由简单的Python类来表示。编辑 polls/models.py 文件,所以 polls/models.py 看起来是这样的:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0)
该代码是直接的。每个模型是django.db.models.Model类的子类。 每个模型具有许多类变量,每一个在模型变量与数据库表的字段关联。
每个字段由 Field 类实例表示 – 例如,CharField表示字符型字段,DateTimeField表示日期时间字段。这告诉Django 每个字段保存的数据类型。
每个Field实例(例如,question_text或pub_date)的名称是字段的名称,这是机器友好的格式。在Python代码中使用这个值,数据库将使用它作为列名。
字段也可以有不同的可选参数;在本示例中,我们已经将票数的默认值设置为0。
最后,需要注意的是关系的定义,这里使用了外键。这告诉 Django 每个选项关联一个问题。 Django支持所有常见的数据库关系:多对一,多对多以及一对之一。
模型代码很小,但表示了 Django 的很多信息。有了它 Django 可以:
为这个应用程序创建数据库(CREATE TABLE语句)
创建访问 Question 和 Choice对象的Python数据库访问API
但首先我们需要告诉 polls 项安装了的应用程序。
再次编辑 mysite/settings.py 文件,并更改INSTALLED_APPS设置包含字符串“polls.apps.PollsConfig”。结果如下所示:
mysite/settings.py文件内容如下:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 INSTALLED_APPS = [ 'polls.apps.PollsConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]现在Django知道 polls 投票程序。让我们运行另一个命令:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 C:\Python27\mysite>python manage.py makemigrations polls Migrations for 'polls': 0001_initial.py: - Create model Choice - Create model Question - Add field question to choice C:\Python27\mysite>
通过运行makemigrations,告诉Django你已经做了模型一些改动(在这种情况下,已经是最新的了),并且你想更改存储作为一个移植。
迁移是Django怎么存储您更改的模型(由你的数据库架构决定)- 它们只是在磁盘上的文件。您如果喜欢可以读取移植新的模型,它在文件 polls/migrations/0001_initial.py。你不会希望Django每一次都读取它们,不过将它们设计成人可编辑的,你要知道Django是如何变化的并手动调整。
还有将运行migrations,自动管理数据库模式(表)命令 - 这就是所谓的迁移,让我们看看SQL了解移植运行。 sqlmigrate 命令将移植名称返回SQL显示:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 $ python manage.py sqlmigrate polls 0001
应该看到类似下面的东西(我们已经重新格式化它的可读性):
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 C:\Python27\mysite>python manage.py sqlmigrate polls 0001 BEGIN; -- -- Create model Choice -- CREATE TABLE "polls_choice" ("id" integer not NULL PRIMARY KEY AUTOINCREMENT, "c hoice_text" varchar(200) not NULL, "votes" integer not NULL); -- -- Create model Question -- CREATE TABLE "polls_question" ("id" integer not NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) not NULL, "pub_date" datetime not NULL); -- -- Add field question to choice -- ALTER TABLE "polls_choice" RENAME TO "polls_choice__old"; CREATE TABLE "polls_choice" ("id" integer not NULL PRIMARY KEY AUTOINCREMENT, "c hoice_text" varchar(200) not NULL, "votes" integer not NULL, "question_id" integ er not NULL REFERENCES "polls_question" ("id")); INSERT INTO "polls_choice" ("choice_text", "votes", "id", "question_id") SELECT "choice_text", "votes", "id", NULL from "polls_choice__old"; DROP TABLE "polls_choice__old"; CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id"); COMMIT; C:\Python27\mysite>
迁移命令将所有还没有被应用的迁移(Django跟踪哪些是使用数据库中的一个特殊的表名为django_migrations应用)运行它们在数据库中 - 基本上是,将使用模型在数据库模式的变化同步。
现在,让我们进入交互式 Python shell 和 Django 所提供的API 。要调用Python命令行,请使用以下命令:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 C:\Python27\mysite>python manage.py shell Python 2.7.10 (default, May 23 2015, 09:44:00) [MSC v.1500 64 bit (AMD64)] on wi n32 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>>
只需键入“python” 来代替,因为manage.py设置DJANGO_SETTINGS_MODULE环境变量,这给Django Python 导入路径到 mysite/settings.py文件。
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 >>> import django >>> django.setup()
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 >>> from polls.models import Question, Choice # import the model classes we just wrote. # No questions are in the system yet. >>> Question.objects.all() [] # Create a new Question. # Support for time zones is enabled in the default settings file, so # Django expects a datetime with tzinfo for pub_date. Use timezone.now() # instead of datetime.datetime.now() and it will do the right thing. >>> from django.utils import timezone >>> q = Question(question_text="What's new?", pub_date=timezone.now()) # Save the object into the database. You have to call save() explicitly. >>> q.save() # Now it has an ID. Note that this might say "1L" instead of "1", depending # on which database you're using. That's no biggie; it just means your # database backend prefers to return integers as Python long integer # objects. >>> q.id 1 # Access model field values via Python attributes. >>> q.question_text "What's new?" >>> q.pub_date datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # Change values by changing the attributes, then calling save(). >>> q.question_text = "What's up?" >>> q.save() # objects.all() displays all the questions in the database. >>> Question.objects.all() [<Question: Question object>]
这里需要等待一会儿. <Question: Question object>完全是这个对象的无用表示。让我们来解决这个问题:通过编辑Question模型(在polls/models.py 文件),并添加一个__str__() 方法到这两个Question 和 Choice 模型:
polls/models.py文件内容如下:# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # only if you need to support Python 2 class Question(models.Model): # ... def __str__(self): return self.question_text @python_2_unicode_compatible # only if you need to support Python 2 class Choice(models.Model): # ... def __str__(self): return self.choice_text
添加 __str__() 方法是非常重要的,使用交互式提示处理添加到模型中,不仅为自己方便,也是因为对象的表示用于整个 Django 自动生成管理。
注意,这些都是正常的Python方法。让我们添加一个自定义的方法,这里只是为了演示:polls/models.py
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 import datetime from django.db import models from django.utils import timezone class Question(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
注意这里增加 import datetime 和from django.utils import timezon,引用Python的标准的datetime模块和Django的时区相关的实用程序在django.utils.timezone,如果不熟悉在Python的时区处理,可以阅读 时区支持文档。
保存这些修改,并再次运行 python manage.py shell 启动一个新的Python交互shell:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 >>> from polls.models import Question, Choice # Make sure our __str__() addition worked. >>> Question.objects.all() [<Question: What's up?>] # Django provides a rich database lookup API that's entirely driven by # keyword arguments. >>> Question.objects.filter(id=1) [<Question: What's up?>] >>> Question.objects.filter(question_text__startswith='What') [<Question: What's up?>] # Get the question that was published this year. >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) <Question: What's up?> # Request an ID that doesn't exist, this will raise an exception. >>> Question.objects.get(id=2) Traceback (most recent call last): ... DoesNotExist: Question matching query does not exist. # Lookup by a primary key is the most common case, so Django provides a # shortcut for primary-key exact lookups. # The following is identical to Question.objects.get(id=1). >>> Question.objects.get(pk=1) <Question: What's up?> # Make sure our custom method worked. >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() True # Give the Question a couple of Choices. The create call constructs a new # Choice object, does the INSERT statement, adds the choice to the set # of available choices and returns the new Choice object. Django creates # a set to hold the "other side" of a ForeignKey relation # (e.g. a question's choice) which can be accessed via the API. >>> q = Question.objects.get(pk=1) # Display any choices from the related object set -- None so far. >>> q.choice_set.all() [] # Create three choices. >>> q.choice_set.create(choice_text='not much', votes=0) <Choice: not much> >>> q.choice_set.create(choice_text='The sky', votes=0) <Choice: The sky> >>> c = q.choice_set.create(choice_text='Just hacking again', votes=0) # Choice objects have API access to their related Question objects. >>> c.question <Question: What's up?> # and vice versa: Question objects get access to Choice objects. >>> q.choice_set.all() [<Choice: not much>, <Choice: The sky>, <Choice: Just hacking again>] >>> q.choice_set.count() 3 # The API automatically follows relationships as far as you need. # Use double underscores to separate relationships. # This works as many levels deep as you want; there's no limit. # Find all Choices for any question whose pub_date is in this year # (reusing the 'current_year' variable we created above). >>> Choice.objects.filter(question__pub_date__year=current_year) [<Choice: not much>, <Choice: The sky>, <Choice: Just hacking again>] # Let's delete one of the choices. Use delete() for that. >>> c = q.choice_set.filter(choice_text__startswith='Just hacking') >>> c.delete()
首先,我们需要创建可以登录到管理界面的用户。运行以下命令:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08c:\python27\mysite> python manage.py createsuperuser
输入你想要的用户名(随便一个),然后按Enter。
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 Username: admin
然后,将提示输入电子邮件地址(随便一个):
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 Email address: xxx@nhooo.com
最后一步是要输入密码。它会要求输入密码两次,第二次为第一的确认。
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 Password: ********** Password (again): ********* Superuser created successfully.
Django管理站点默认激活。让我们启动开发服务器,并探索它。
如果服务器未运行,启动它,如下所示:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 c:\python27\mysite>python manage.py runserver
现在,打开Web浏览器,进入“/admin/” 本地域名- 例如, http://127.0.0.1:8000/admin/ 应该看到管理员登录界面:
由于移在默认情况下开启,登录屏幕可能会显示在你自己的语言, 由于翻译在默认情况下开启,登录屏幕可能会显示在你自己的语言,
现在,尝试与在上一步中创建的超级用户帐号登录。应该会看到 Django 管理的首页:
你应该看到一些可编辑内容:组和用户。它们由django.contrib.auth,Django的认证框架提供。
poll应用程序在哪里?它不会显示在管理索引页面上。
只有一件事要做:我们需要告诉管理员这个Question对象有一个管理界面。要做到这一点,打开 polls/admin.py文件,并修改它如下:
# Filename : example.py # Copyright : 2020 By Nhooo # Author by : www.nhooo.com # Date : 2020-08-08 from django.contrib import admin from .models import Question admin.site.register(Question)
现在,我们已经注册Question,Django知道它应该在管理主页面上显示:
点击“Questions”。现在,在“change list”页面查看问题。该页面显示数据库中的所有问题,并允许您选择其中一个进行更改。还有我们先前创建的问题:
点击“What's new?”这个问题进行编辑:
需要注意的事项在这里列出:
表单是从问题(Question)模型自动产生。
不同型号的字段类型(DateTimeField,CharField)对应相应的HTML输入部件。每个字段类型知道自己在Django管理中如何显示。
每个DateTimeField字段得到 JavaScript 快捷方式。日期得到一个“Today”的快捷方式并且弹出日历,并多次获得了“Now”快捷方式并弹出窗口,列出了常用的输入时间。修改“Date published”点击“Today”和“Now”快捷方式。然后点击“Save and continue editing.”,然后点击“History”在右上角。你会看到一个页面,列出通过Django管理到这个对象的所有变化,修改人用户名和时间戳: 代码下载: http://pan.baidu.com/s/1jGR3wDg