django的基础知识
在settings.py文件中,settings文件中顶部的INSTALLED_APPS
设置项。它列出了所有的项目中被激活的Django应用(app)。你必须将你自定义的app注册在这里。每个应用可以被多个项目使用,并且可以打包和分发给其他人在他们的项目中使用。
默认情况,INSTALLED_APPS
中会自动包含下列条目,它们都是Django自动生成的:
- django.contrib.admin:admin管理后台站点
- django.contrib.auth:身份认证系统
- django.contrib.contenttypes:内容类型框架
- django.contrib.sessions:会话框架
- django.contrib.messages:消息框架
- django.contrib.staticfiles:静态文件管理框架
这些应用文件需要建立一些数据库表,我们需要在终端中使用命令创建数据库表:
$ python manage.py migrate
migrate命令将遍历INSTALLED_APPS
设置中的所有项目,在数据库中创建对应的表,并打印出每一条动作信息
Django模型model
模型本质上就是数据库表的布局,再附加一些元数据。
Django通过自定义Python类的形式来定义具体的模型,每个模型的物理存在方式就是一个Python的类Class,每个模型代表数据库中的一张表,每个类的实例代表数据表中的一行数据,类中的每个变量代表数据表中的一列字段。Django通过模型,将Python代码和数据库操作结合起来,实现对SQL查询语言的封装。
# polls/models.py 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)
实例
这个例子中,每一个字段都是Field
类的一个实例,例如用于保存字符数据的CharField和用于保存时间类型的DateTimeField,它们告诉Django每一个字段保存的数据类型。
最后请注意,我们使用ForeignKey
定义了一个外键关系。它告诉Django,每一个Choice关联到一个对应的Question(注意要将外键写在‘多’的一方)。Django支持通用的数据关系:一对一,多对一和多对多
启用模型
Django在我们启动命令时,会做两件事:
- 创建该app对应的数据库表结构
- 为Question和Choice对象创建基于Python的数据库访问API
$ python manage.py makemigrations polls
启动命令前应该先makemigrations一下。通过运行makemigrations
命令,相当于告诉Django你对模型有改动,并且你想把这些改动保存为一个“迁移(migration)”。
migrations
是Django保存模型修改记录的文件,这些文件保存在磁盘上。在例子中,它就是polls/migrations/0001_initial.py
,你可以打开它看看,里面保存的都是人类可读并且可编辑的内容,方便你随时手动修改。
$ python manage.py sqlmigrate polls 0001
继续运行指令
$ python manage.py migrate
migrate命令对所有还未实施的迁移记录进行操作,本质上就是将你对模型的修改体现到数据库中具体的表上面。Django通过一张叫做django_migrations的表,记录并跟踪已经实施的migrate动作,通过对比获得哪些migrations尚未提交。
migrations的功能非常强大,允许你随时修改你的模型,而不需要删除或者新建你的数据库或数据表,在不丢失数据的同时,实时动态更新数据库。记住修改模型时的操作分三步:
- 在models.py中修改模型;
- 运行
python manage.py makemigrations
为改动创建迁移记录; - 运行
python manage.py migrate
,将操作同步到数据库。
之所以要将创建和实施迁移的动作分成两个命令两步走是因为你也许要通过版本控制系统(例如github,svn)提交你的项目代码,如果没有一个中间过程的保存文件(migrations),那么github如何知道以及记录、同步、实施你所进行过的模型修改动作呢?毕竟,github不和数据库直接打交道,也没法和你本地的数据库通信。但是分开之后,你只需要将你的migration文件(例如上面的0001)上传到github,它就会知道一切。
使用模型的API
$ python manage.py shell
输入如上指令即可进入Python中的Django shell界面,调用manage.py
参数能将DJANGO_SETTINGS_MODULE
环境变量导入,它将自动按照mysite/settings.py
中的设置,配置好python shell环境。这样,我们就可以导入和调用任何项目内的模块了。
进入shell中,尝试下面的API:
>>> from polls.models import Question, Choice # 导入我们写的模型类
# 现在系统内还没有questions对象
>>> Question.objects.all()
<QuerySet []> # 创建一个新的question对象
# Django推荐使用timezone.now()代替python内置的datetime.datetime.now()
# 这个timezone就来自于Django唯一的依赖库pytz
from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now()) # 你必须显式的调用save()方法,才能将对象保存到数据库内
>>> q.save() # 默认情况,你会自动获得一个自增的名为id的主键
>>> q.id
1 # 通过python的属性调用方式,访问模型字段的值
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>) # 通过修改属性来修改字段的值,然后显式的调用save方法进行保存。
>>> q.question_text = "What's up?"
>>> q.save() # objects.all() 用于查询数据库内的所有questions
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>
shell API command
这里等一下:上面的<Question: Question object>
是一个不可读的内容展示,你无法从中获得任何直观的信息,为此我们需要一点小技巧,让Django在打印对象时显示一些我们指定的信息。
返回polls/models.py
文件,修改一下question和Choice这两个类,代码如下:
from django.db import models
from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible # 当你想支持python2版本的时候才需要这个装饰器
class Question(models.Model):
# ...
def __str__(self): # 在python2版本中使用的是__unique__
return self.question_text @python_2_unicode_compatible
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
这个技巧不但对你打印对象时很有帮助,在你使用Django的admin站点时也同样有帮助。这样提高了Django的版本兼容性
另外,这里我们自定义一个模型的方法,用于判断问卷是否最近时间段内发布度的:
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)
这里在return中实现了条件筛选返回。在实际开发中可以更灵活的使用来产生更高的开发效率。
保存修改后,我们重新启动一个新的python shell,再来看看其他的API:
>>> from polls.models import Question, Choice # 先看看__str__()的效果,直观多了吧?
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]> # Django提供了大量的关键字参数查询API
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]> # 获取今年发布的问卷
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?> # 查询一个不存在的ID,会弹出异常
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist. # Django为主键查询提供了一个缩写:pk。下面的语句和Question.objects.get(id=1)效果一样.
>>> Question.objects.get(pk=1)
<Question: What's up?> # 看看我们自定义的方法用起来怎么样
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True # 让我们试试主键查询
>>> q = Question.objects.get(pk=1) # 显示所有与q对象有关系的choice集合,目前是空的,还没有任何关联对象。
>>> q.choice_set.all()
<QuerySet []> # 创建3个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对象可通过API访问和他们关联的Question对象
>>> c.question
<Question: What's up?> # 同样的,Question对象也可通过API访问关联的Choice对象
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3 # API会自动进行连表操作,通过双下划线分割关系对象。连表操作可以无限多级,一层一层的连接。
# 下面是查询所有的Choices,它所对应的Question的发布日期是今年。(重用了上面的current_year结果)
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # 使用delete方法删除对象
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
another API case
模型使用是实现动态网站和数据库交互的核心,更是Django项目的核心。要重点理解。
part4 表单和类视图部分
1.表单
先贴上polls/detail.html代码
<h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
要点总结:
1.在form表单中属性,action指要发送的目标url,method表示要提交数据的方式(get或post)
2.对于form表单发送post请求,必须考虑一个跨站请求伪造的安全问题,要在form表单内添加一条{% csrf_token %}标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。这个方法对form表单的提交方式方便好使,但如果是用ajax的方式提交数据,那么就不能用这个方法了。
小问题:ajax方式提交数据如何防范CSRF攻击?
3.forloop.counter是Django提供的一个用于计算当前循环次数的变量,还有给循环项目添加有序数标的功能。
4.表单:上面的模板显示一系列单选按钮,按钮的值是选项的ID,按钮的名字是字符串"choice"。这意味着,当你选择了其中某个按钮,并提交表单,一个包含数据choice=#
的POST请求将被发送到指定的url,#
是被选择的选项的ID。这就是HTML表单的基本概念。
对于vote视图函数(polls/views.py)源码:
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from .models import Choice, Question
# ... def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# 发生choice未找到异常时,重新返回表单页面,并给出提示信息
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
要点注意:
1.这里的request.POST是一个类似字典的对象。允许我们通过通过key访问对应的值。本例中,request.POST['choice']返回的值是一个string字符串,即使是一个数字,也不是整形,都是字符串类型。
2.当处理用户的动作,计数器加一后,通过HttpResponseRedirect跳转到一个新的页面。为何这里不用Httpresponse?因为这样用户对是否完成动作没有好的体验。
HttpResponseRedirect中需要一个目标url参数。一个良好的编程习惯:当处理完POST请求后,应用HttpResponseRedirect返回一个响应,不仅仅对Django来说是这样。
3.Django中处理http请求-响应流程:都是通过路由分发,视图处理,模板渲染,模型这几个流程。
如何利用类视图减少重复代码?
为了处理views.py中类似的功能代码,我们利用Django提供的偷懒方式:类视图
先将urls.py中的代码修改下,改成类似这样的
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
接下来修改views.py中的函数,将def function()函数改为class function(object)类函数。需要先调用django.views中的generic函数。generic函数中还有两个子函数,DetailView与ListView,在类函数中是需要作为父类继承来的。
关于静态文件
我试着按照教程给网页添加背景图片。
首先创建css样式表。在polls目录中创建一个static
目录。Django将在那里查找静态文件,这与Django在polls/templates/中寻找对应的模板文件的方式是一致的。
Django的STATICFILES_FINDERS
设置项中包含一个查找器列表,它们知道如何从各种源中找到静态文件。
在刚才的static
目录中新建一个polls
子目录,再在该子目录中创建一个style.css
文件。换句话说,这个css样式文件应该是polls/static/polls/style.css
。你可以通过书写polls/style.css
在Django中访问这个静态文件,与你如何访问模板的路径类似。这里涉及到了一个知识点:静态文件的命名空间。简单来说就是,Django在项目目录下寻找与导入同名的静态文件。若目录下存在多个不同应用,不同应用中还存在两个同名的静态文件(这很有可能!),那Django将会使用它找到的第一个匹配的静态文件,这样很容易导致加载错误。为了避免这种问题,我们可以在应用下添加命名空间,也就是说,将这些静态文件放进以它们所在的应用的名字同名的另外一个子目录下。这样就解决了问题。
在polls/static/polls/
目录下创建一个用于存放图片的images
子目录,在这个子目录里放入`background.gif文件。换句话说,这个文件的路径是polls/static/polls/images/background.gif。之后再css文件中添加
body {
background: white url("images/background.gif") no-repeat right bottom;
}
同时在index.html文件中最顶部声明
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
但是随后刷新时候出现问题,发现网页显示不出背景图片,先查了下开发者工具里显示的500错误,图片加载失败。我上网查找了下原因,发现可能是setting.py设置的静态文件路径出了问题,原来的静态路径是
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR ,"static") #实际名 ,即实际文件夹的名字
)
然后我更改成为
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(os.path.dirname(__file__), '../static/').replace('\\','/'),
)
刷新后图片显示正常!看来是静态文件的路径设置出了问题,导致并没有按照预定找到路径。
part7 通过admin页面更好的管理
分开显示:
polls/admin.py
from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
] admin.site.register(Question, QuestionAdmin)
把一对多关联显示,这里额外显示3个
polls/admin.py
from django.contrib import admin from .models import Choice, Question class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3 class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin)
choice列展示换位横向展示
class ChoiceInline(admin.TabularInline):
在数据列表里面展示更多的信息,字段和方法都可以
list_display = ('question_text', 'pub_date', 'was_published_recently')
点击字段名是自带排序的,除了方法,没有确定的返回值,不能排序,我们可以这样
定义某字段的排序值为别的值,
改变值为布尔值
改变字段显示名称
class Question(models.Model):
# ...
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
添加一个筛选条件
list_filter = ['pub_date']
因pub_date是一个DateTimeField字段,所以Django自动添加了几个时间过滤器。
添加一个搜索条件,似乎只能添加一个字符串的搜索条件
search_fields = ['question_text']
查找import包的路径,比如django
python -c "import django; print(django.__path__)"
设定项目自己的templates
mysite/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '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',
],
},
},
]
在manage.py同目录下创建templates/admin。复制django自带的目录下的base_site.html复制到admin文件下,改变内容
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}
项目会自动覆盖原django的文件,而展示这个文件内容,一般最重要的是admin下的index.html,也可以像这样覆盖。
关于反向查询
django表结构中,可以设置OneToOne,ManyToMany,ManyToOne多种关联关系。这是ORM的强大之处。
一对多反向查询用__set,一对一反查用句点属性标识法加上小写的表的名字,多对多反查可以用select_related或.all。
还有一点,在views视图函数胡中能从request对象中获取到的数据,在前端模板中也都能获取到。
参考:http://www.liujiangblog.com/course/django/88 很好的Django学习教程!
django的基础知识的更多相关文章
- Django模板-基础知识
上一篇中带参数的URLconf虽然可以做到传参动态显示内容,但是最终现实的内容还是硬编码到Python代码中的 def hours_ahead(request,phours): try: phours ...
- 【Django】--基础知识
一 什么是web框架? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. Web应 ...
- Django框架基础知识01-配置环境
Django框架 Django是个怎样的东西呢? Web应用框架----Django http服务器:用来接受用户请求,并将请求转发给web应用框架进行处理. Web应用框架处理完以后再发送给htt ...
- Django框架基础知识14-类视图
MTV view视图 wsgi函数 def index(request): .... return HttpResponse() 特定的HTTP方法.get,post可以定义单独的方法 继承,多继承, ...
- Django框架基础知识13-auth系统
我们昨天登录admin时创建的用户信息是存放在哪里了呢? auth系统的数据表: 从表的名称我们就能看出, auth_user,auth_group,auth_permission分别存放了用户,用户 ...
- Django框架基础知识12-中间件及上下文处理器
Django中间件(Middleware) 是一个轻量级.底层的“插件”系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出. django 中的中间件(middleware) ...
- Django框架基础知识11-会话状态保持及表单
浏览器存储cookie的方式不太安全,那有没有更好些的来存储登入状态的方式呢??? 状态保持----cookie和session: 状态保持: 1.http协议是无状态的:每次请求都是一次新的请求,不 ...
- Django框架基础知识10-内置分页系统
from django.shortcuts import render, redirect, reversefrom datetime import datetime# Create your vie ...
- Django框架基础知识09-请求与响应
视图函数接受到的request到底是个什么对象呢? HttpRequest对象: 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象视图函数的第一个参数是HttpRequest ...
随机推荐
- JDBCTool
新建 *.properties属性文件,内容如下: driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/dbName userna ...
- 基于区域的全卷积神经网络(R-FCN)简介
在 Faster R-CNN 中,检测器使用了多个全连接层进行预测.如果有 2000 个 ROI,那么成本非常高. feature_maps = process(image)ROIs = region ...
- UVA11624(bfs最短路)
Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the m ...
- 微软silverlight Analytics FrameWork
本文转自:http://kevinfan.blog.51cto.com/1037293/334622/ http://kevinfan.blog.51cto.com/1037293/334622 ...
- TypeScript完全解读(26课时)_5.TypeScript完全解读-函数
5.TypeScript完全解读-函数 新建function.ts.然后在index.ts内引用 给函数定义参数类型:上面是es5的写法 下面是ts6的写法 一个完整的函数类型.括号 箭头 numbe ...
- IDL(Interactive Data Language——交互式数据语言)
Interactive Data Language——交互式数据语言 目前,图像处理常用的ENVI就是用IDL开发的经典软件 广泛支持的平台: Microsoft Windows Open VMS S ...
- 挨踢职场求生法则-----我在IT职场打滚超过15年了,从小小的程序员做到常务副总
摘要我在IT职场打滚超过15年了,从小小的程序员做到常务副总.相对于其它行业,IT职场应该算比较光明的了,但也陷阱重重,本文说说我的亲身体会,希望大家能在IT职场上战无不胜! 通用法则 法则1:忍耐是 ...
- HDU - 2036 改革春风吹满地 叉乘法求多边形面积
改革春风吹满地 “ 改革春风吹满地, 不会AC没关系; 实在不行回老家, 还有一亩三分地. 谢谢!(乐队奏乐)” 话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟 ...
- SqlServer2012——Select,分组,排序、插入
1.select 简单语句 --select语句 * --select子句 * AS result --select子句,可以将结果保存在result中 ~~~~~~~~~~~~~~~~~~~~~~~ ...
- 洛谷 - P1582 - 倒水 - 位运算
https://www.luogu.org/problemnew/show/P1582 要求用最少的瓶子,那肯定不能有两个一样的瓶子,否则合并更优. 枚举其二进制位,每次加上lowbit,将最后一个1 ...