(二)
Copy # project_name/urls.py
from django.urls import path
from django.contrib import admin
from app_name import views
urlpatterns = [path('app_name/', views.index), path('admin/', admin.site.urls)]
到底urlpatterns是如何分割访问的url的?其次path中的name可有可无吗?有什么作用?
在方式一中,是不是进行了两次url的分割匹配?
path详解
Copy path(route, view, kwargs, name)
route:类似于正则表达式,用来匹配url中‘?’前的部分,也就是不包括get和post请求
view:当找到匹配的url后,会调用view并传入一个HttpRequest对象
name:为url取名,并可以在django任何地方任意地引用它
urlpatterns可能有多个path,每个path匹配一段url后可能会有一些返回值,这些返回值如何组合?还是说只能匹配其中的一个path,一旦匹配处理之后,就会形成结果?name的引用还是没有清楚的概念,不知道如何使用
settings.py文件
Copy python manage.py migrate
在使用应用(不论是默认还是新创)的时候,至少需要在数据库创建一张表,该命令只会创建在INSTALLED_APPS中声明的应用。
创建模型应该是开发web应用的第一步,也就是数据库结构设计和附加的其它元数据
Copy # app_name/models.py
from django.db import models
class Table_name(models.Model):
# field_name = data_type(limitation)
string = models.CharField(max_length=200)
number = models.IntegerField(default=0)
date = models.DateField('Datetime')
class Table_name_2(models.Model):
table_1 = models.ForeignKey(Table_name, on_delete=models.CASCADE)
number = models.IntegerField(default=0)
据说Datetime是一个可选选项,所谓可选就是为变量添加一个人类友好的名字,那这个人类友好名到底在什么时候会被使用?是在web界面吗?这个外键中‘on_delete=models.CASCADE’是什么意思?(好像是一对一的关系,那其他类型如何表示?)
Copy INSTALLED_APPS = ['app_name.apps.App_nameConfig',]
之前有提到过把app应用放进settings中INSTALLED_APPS的,但目前看到使用这一部分的也只有与数据库相关的,所以是否可以理解为不涉及数据库的时候,不放入该列表也可以?
Copy python manage.py makemigrations app_name
这部分还未涉及到数据库的改变,而是把模型前后变化存储在“迁移”这种形式之中,当再次使用python manage.py migrate
命令的时候,才会将这些未执行的迁移与数据库同步。
models.py
文件,改变模型。
运行python manage.py makemigrations
为模型的改变生成迁移文件。
运行python manage.py migrate
来应用数据库迁移。
为什么要存在迁移?直接使用前面的命令,同步到数据不就可以吗?
Thereasonthatthereareseparatecommandstomakeandapplymigrationsisbecauseyou'llcommitmigrationstoyourversioncontrolsystemandshipthemwithyourapp;theynotonlymakeyourdevelopmenteasier,they'realsousablebyotherdevelopersandinproduction.
据说原因是为了版本开发系统,也就是方便开发,可是暂时还是不能理解。
如果我把models.py定义好,并且把app加入到settings.py中,但是没有做migrate的命令,直接开启运行服务,会报错吗?也即是说,在开启服务时,会不会自动同步数据库?
API,djangoshell
Copy python manage.py shell
使用shell的优点还不清楚
Copy >>> from app_name.models import Table_name, Table_name_2
>>> Table_name.objects.all() # 查看已创建的Table_name
<QuerySet []> # 当没有创建时,返回空列表
>>> from django.utils import timezone
>>> t0 = Table_name(string = 'Hello World', number = 1, date = timezone.now())
>>> t0.save() # save到数据库
>>> t0.id
1
>>> t0.string
'Hello World'
>>> t0.number
1
>>> t0.string = 'Bye World'
>>> t0.save()
之前觉得没什么用,后来发现可以直接操作数据库,也就是说通过migrate,在数据库中建立了表和字段,然后使用shell可以手动添加数据到里面去,当然也可以查询数据库中的数据 。可是,做这个应用不是要从别人的访问中得到数据吗?比如说这个投票应用,数据的来源应该是网上访问的人,所以也就是只能通过shell查看一下数据了吧?
Copy # 优化类的显示
# app_name/models.py
from django.db import models
class Table_name(models.Model):
....
def __str__(self):
return self.string
django数据库管理:shell
此外也可以使用shell进行查询,基本上还是前面和数据库交互的内容
Copy >>> from app_name.models import Table_name, Table_name_2
>>> from django.utils import timezone
>>> Table_name.objects.all()
>>> Table_name.objects.filter(field_name = field_value) # 得到符合条件的类的列表
>>> Table_name.objects.get(field_name = field_value) # 得到特定的类,不存在时报错
>>> q = Table_name.objects.get(pk=1) # pk是primary key,主键
# 假设Table_name中的主键是Table_name_2的外键
>>> q.table_name_2_set.all() # 所有table2中以q为外键的行
>>> q.table_name_2_set.create(field = field_value...) # 可以通过外键来创建,这样不用设置外键
>>> q.table_name_2_set.count() # 还可以计算以q为外键的行的个数
>>> Choice.objects.filter(question__pub_date__year=current_year)
Copy >>> Choice.objects.filter(question__pub_date__year=current_year)
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
居然还可以这样操作?那这样来说choice中外键存储的就不是简单的question中的主键值,而是把整个question实例对象作为值
django数据库管理:管理界面
Copy python manage.py createsuperuser
Copy Username: adminEmail
address: admin@example.com
Password: **********
Password (again): *********
Superuser created successfully.
如果在管理界面看到自己的应用,还要修改
Copy # app_name/admin.py
from django.db import admin
from .models import Table_name
admin.site.register(Table_name)
这里的添加应用只是为了让管理人员在可视化的环境下工作吧?即便不进行这一步,是不是也可以完成整个web应用的正常运行呢?
进一步优化视图,视图包括两点:实现特定功能,模板,目前还不知道模板如何使用,视图往往对应不同的网页
在Django中,网页和其他内容都是从视图派生而来。
如果说视图指的是网页中对应操作的具体实现,我可以理解,但整个网页U又是如何制作的呢?(虽然已经涉及到前端了),另外前端和视图之前的数据和功能连接是如何实现的呢?
为了将URL和视图关联起来,Django使用了'URLconfs'来配置。URLconf将URL模式映射到视图。
此外还有URL调度器,有时间可以详细了解一下。
较复杂的视图
Copy # app_name/views.py
from django.http import HttpResponse
# 查看问题的详细信息
def detail(request, question_id):
return HttpResponse(f'you are looking for the detail of {question_id}')
# 查看投票结果
def results(request, question_id):
return HttpResponse(f'you are looking for the results of {question_id}')
# 实现投票
def vote(request, question_id):
return HttpResponse(f'you are voting on {question_id}')
Copy # app_name/urls.py
from django.url import path
from . import views
urlpatterns = [path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id/>/vote/', views.vote, name='vote')]
name到底什么用?
视图应该返回HttpResponse对象或者异常,那么如果我要返回一个pdf文件或者一个其他格式的数据,也要放在HTTPResponse对象之中吗?
Copy # app_name/views.py
from django.http import HttpResponse
from .models import Question # Field_name
from django.template import loader
def index(request):
latest_question_list = Question.order_by('-pub_date')[:5]
template = loader.get_template('app_name/index.html')
context = {'latest_question_list': latest_question_list,}
return HttpResponse(template.render(context, request))
这里明明是‘pub_date’,为什么前面要加‘-’
如果想要修改网页的样式,就要用到模板了
Copy # app_name/templates/app_name/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/app_name/{{question.id}}">{{question.question_text}}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No app_name are available.</p>
{% endif %}
虽然我们现在可以将模板文件直接放在polls/templates文件夹中(而不是再建立一个polls子文件夹),但是这样做不太好。Django将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django没有办法区分它们。我们需要帮助Django选择正确的模板,最简单的方法就是把他们放入各自的命名空间中,也就是把这些模板放入一个和自身应用重名的子文件夹里。
确实不能理解其中的意思,主要的问题在于在模板之下的app目录到底是如何起到区分不同模板的,如果是遍历,就会忽略文件名,如果不是,那它说也可以不用这个目录,那找不到目录不会导致报错吗?如何没有问题,很好奇是如何做到的?
另外,这个HTML!?真的看不懂!据说html的结构中可以运行、获取后台代码或值,可以写服务器端代码,但这也太奇怪了,必须了解细节。
还有对于Question类的使用,是否意味着所有程序都可以实现与数据库的互动,而不只是在shell或管理平台才可以?
在使用模板时,和之前的区别大概有三点:1)使用loader导入模板 2)将模板所需的变量或对象(上下文变量)存储在context中 3)编写html文件,其中会用很多`
`类的代码来动态输出网页,由于这几个操作经常使用,所以有了快捷render函数
Copy # app_name/views.py
from django.shorcuts import render
from .models import Question
def detail(request):
latest_question_list = Question.objects.order_by('-pb_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'app_name/detailhtml', context)
一个异常加一个html输出
Copy # app_name/views.py
from django.http import Http404
from django.shorcuts import render
from .models import Question
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404('Question does not exist')
return render(request, 'app_name/detail.html', {'question':question})
Copy # app_name/templates/app_name/detail.html
{{question}}
好像也对,他是不是直接找到了内层的‘app_name/detail.html’呢?这样合理一些,之前说了为了避免不同应用html重名的问题,这里倒是可接受了,在templates文件夹里,假设有两个重名html文件,只需要‘app_name1/html’和‘appname2/html’就不出现重复的情况,但是问题还是为什么不同应用的重名文件会放在其中一个应用的templates文件夹里呢?模板文件夹又不是公共空间,而是在每个应用底下单独创建,为什么会有别的应用的html文件?
简化版get_object_or_404()
Copy # app_name/views.py
from django.shorcuts import get_objects_or_404, render
from .models import Question
def details(request, question_id):
question = get_objects_or_404(Question, pk=question_id)
return render(request, 'app_name/detail.html', {'question': question})
还有get_list_or_404()
,只是get被换成了filter 这里关键其实是空是否合法,假如我要查到的结果允许为空,也就是那是正常的,这里的报错是不是就..其实也不应该这样讲,空可以从是否异常来判断,也就是说把这部分判断放到外面来做就是了,都一样。
完全版模板系统
Copy # app_name/templates/app_name/detail.html
<h1>{{ question.question_context}} </h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
如果不学习模板语言的话,应该是不能熟练制作网页的,这也是学习django看不到的必要知识。
模板中的硬编码url 回想index.html,其中每个问题的链接的形式,被他们称为“硬编码和强耦合的链接”,一看到这样的名词,我都想抽自己一巴掌。。。 Ok,接下来,我们会看到url的name终于体现出它的作用了
Copy # part code of app_name/index.html
<li><a href="% url 'detail' question.id %">{{question.question_text}}</a></li>
原本url的定义是
Copy path('<int:question_id>/', views.detail, name='detail'),
为了方便比较,原本是'/app_name/',那么datail代表的到底是那部分的url?奥,我知道了,它虽然匹配了一个整数,但是代表的url中并不包括整数那部分,而是整数前的部分
如果你想改变投票详情视图的 URL,比如想改成 polls/specifics/12/ ,你不>用在模板里修改任何东西(包括其它模板),只要在 polls/urls.py 里稍微修改>一下就行:
Copy # added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
多个项目url名称重复问题
首先,在url文件中添加‘app_name='app_name'’,其次修改html文件中的url引用为{% url 'app_name:detail'}