Django-MVT
(1) View python version:
python -m django --version
(2) Create a Django project
django-admin startproject mysite
(3) successful test development server
Desktop\bncDjango\mysite>python manage.py runserver
Django comes with a writing pure Python lightweight Web server. In order to let you quickly develop what they want, because you do not need production-level server configuration work (such as Apache) terms, unless you are ready to put into the production environment. Never will this server be used anywhere and production of environment-related. The server just for the development and design. (We are specialists in Web framework, not in terms of the Web server.)
(4) create application modules
python manage.py startapp polls
Application definition
INSTALLED_APPS = [
'django.contrib.admin', # 管理员站点
'django.contrib.auth', # 认证授权系统
'django.contrib.contenttypes', # 内容类型框架
'django.contrib.sessions', # 会话框架
'django.contrib.messages', # 消息框架
'django.contrib.staticfiles', #管理静态文件的框架
'polls', # 投票模块]
(5) the view edit view polls Model
from django.shortcuts import render
Create your views here.
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello,this is my frist polls index.")
Mapping the url (6) polls module
from django.urls import path
from . import views
urlpatterns = [
path('', views.index,name='index'),]
Url the configuration (7) mysite main module
from django.contrib import admin
from django.urls import path,include # 注意导入include模块
urlpatterns = [
path('polls/', include('polls.urls')), # 配置polls子模板url,支持正则
path('admin/', admin.site.urls),]
(8) query page http: // localhost: 8000 / polls /
(9) database configuration and migration
DATABASES = {
'default': {
# 'django.db.backends.sqlite3',
# 'django.db.backends.postgresql',
# 'django.db.backends.mysql',
# 'django.db.backends.oracle'
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
# MySQL数据库配置
# 'mysql': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'all_news', # 数据库名
# 'USER': 'root',
# 'PASSWORD': 'root',
# 'HOST': '127.0.0.1',
# 'PORT': '3306',
# }
}
python manage.py migrate
(10) the preparation of model M
from django.db import models
Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_data = models.DateField('date published')
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question,on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
(11) activation model
Generate migrate files to change the model
python manage.py makemigrations polls
Another view, select, execute name to receive a migration, then returns the corresponding SQL
python manage.py sqlmigrate polls 0001
Application database migration
python manage.py migrate
(12) Automatic admin page
12.1 can create a login user management page, both admin
python manage.py createsuperuser
12.2 start the development server:
python manage.py runserver
http://127.0.0.1:8000/admin/login/?next=/admin/
12.3 Enter site
12.4 Application Configuration Management page added
from django.contrib import admin
Register your models here.
from .models import Question,Choice
admin.site.register(Question)
admin.site.register(Choice)
(13) write more views
views at 13.1 polls
from django.shortcuts import render
from django.http import HttpResponse
问题索引页
def index(request):
return HttpResponse("Hello,this is my frist polls index.")
问题详情页
def detail(request,question_id):
return HttpResponse("You're looking at question %s." % question_id)
问题结果页
def results(request,question_id):
return HttpResponse("You're looking at the results of question %s." % question_id)
投票处理器
def vote(request,question_id):
return HttpResponse("You're voting on question %s." % question_id)
Urls at 13.2 polls remember to add the namespace
from django.urls import path
from . import views
app_name = 'polls' #添加命名空间
urlpatterns = [
# ex: /polls/
path('', views.index,name='index'),
# ex: /polls/5/
path('
# ex: /polls/5/results/
path('
# ex: /polls/5/vote/
path('
13.3 query database information and display the page
问题索引页
def index(request):
latest_question_list = Question.objects.order_by('pub_data')[:3]
output = '
'.join([q.question_text for q in latest_question_list])
HttpResponse(template.render(context,request))
return HttpResponse(output)
(14) the preparation of template T
14.1 created under mysite templates, and create polls folder, create a index.html
<!DOCTYPE html>
{% if latest_question_list %}
- {{ question.question_text }}
{% for question in latest_question_list %}
{% endfor %}
{% else %}
No polls are available.
{% endif %}
It can be modified (common) would like to change. polls/specifics/12/
You do not change anything in the template (including other template), as long as polls/urls.py
a little tinkering on the line:
{% for question in latest_question_list %}
{{ question.question_text }}
{% endfor %}
14.2 modify the settings mysite of DIRS
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'template/')],
'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',
],
},
},]
14.3 polls / views.py modification
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
from polls.models import Question
问题索引页
def index(request):
latest_question_list = Question.objects.order_by('pub_data')[:5]
# output = '
'.join([q.question_text for q in latest_question_list])
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context,request))
It is further modified to (common):
问题索引页
def index(request):
latest_question_list = Question.objects.order_by('pub_data')[:5]
context = {'latest_question_list': latest_question_list}
return render(request,'polls/index.html',context)
Access 14.4 "/ polls /" in your browser to view:
(15) View detail page
Under 15.1 polls views.py
from django.http import Http404
问题详情页
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,'polls/detail.html', {'question':question,'question_id':question_id})
Algorithm (used) optimized
from django.shortcuts import render,get_object_or_404
问题详情页
def detail(request,question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question,'question_id':question_id})
15.2 template下detail.html
<!DOCTYPE html>
{{ question.question_text }}
{% for choice in question.choice_set.all %}
- {{ choice.choice_text }}
{% endfor %}
15.3 operating results
(16) polls / detail.html detail page add a form form
{{ question.question_text }}
{% if error_message %}
{{ error_message }}
{% endif %}
Each radio button
value
attribute corresponding to the respective Choice's ID. Each radio buttonname
Shi"choice"
. This means that when someone chooses a radio button and submit the form submission, it will send a POST datachoice=#
, where # is the selected Choice of ID. This is the basic concept of the HTML form.- We set the form
action
to{% url 'polls:vote' question.id %}
, and setmethod="post"
. Use method = "post" is very important because this will change the behavior of the submission form data on the server side. When you need to change the form to create a server-side data, use `method="post"
. This is not specific skills of Django; this is an excellent web development skills. forloop.counter
Indicatingfor
label has cycled many times.As we create a POST form (which has the effect of modifying data), so we need to be careful cross-site request forgery. Thankfully, you do not have to worry too much, because Django already has a system to defend against it very easy to use. In short, for all the internal URL of the POST form should use
{% csrf_token %}
template tags.
(17) polls/views.py
View Edit
投票处理器
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):
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,)))
request.POST
It is a dictionary-like object, so you can get the data submitted by name keywords. In this example,request.POST['choice']
go back and select a string Choice's ID.request.POST
The value is always a string.- If you
request.POST['choice']
do not provide the datachoice
, POST will lead to aKeyError
. The above code checksKeyError
, if not givenchoice
the form and redisplay Question an error message. - After the increase of the number of votes Choice, a code is returned
HttpResponseRedirect
instead of the usualHttpResponse
,HttpResponseRedirect
receives only one parameter: the user will be redirected in the URL. Using the constructorreverse()
functions. This function avoids us hard-coded URL in the view function. The URL will redirect calls'results'
view to display the final page.
(18) redirects results.html
from django.shortcuts import get_object_or_404, render
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
(19) General view refactoring
19.1 detail()
view is almost identical. The only difference is the name of the template.
问题索引页
def index(request):
latest_question_list = Question.objects.order_by('pub_data')[:5]
return render(request,'polls/index.html',{'latest_question_list': latest_question_list})
问题详情页
def detail(request,question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question,'question_id':question_id})
问题结果页
def results(request,question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
19.2 Creating a polls/results.html
template
{{ question.question_text }}
{% for choice in question.choice_set.all %}
- {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
{% endfor %}
19.3 General view of the system
General view of the common mode of abstraction, you can make when writing applications do not even need to write Python code. Convert our poll application to use the generic views system, so we can remove a lot of our code. We just need to do the following steps to complete the conversion,
- Conversion URLconf.
- Delete some of the old view is no longer needed.
- Introducing new view based on a common view of Django
1 modified URLconf
Open polls/urls.py
the URLconf and it is modified to: the path name string has been matched by the pattern <question_id>
changed <pk>
.
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('
path('
path('
2 Improved view
Remove the old index
, detail
and results
the view, and replaced with generic views Django. Open the polls/views.py
file and modify it to:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.order_by('pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
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):
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,)))
- Each generic view needs to know which model it will act on. This is done by
model
providing property. DetailView
We expect to capture from the URL named"pk"
primary key, so we put the generic viewquestion_id
changedpk
.
19.4 run the program
main page
Subpage
Details page
(20) automated testing
20.1 Testing Strategies
- Test drive: the first to write tests before you write code. Development methodology "test drive" the only problem will be described in the abstract test case for Python.
- More generally the case that a novice new to automated testing more inclined to write the code, and then write the test.
- If you only write thousands of lines of Python code, choose where to start writing tests really very simple. If this is the case, then write a test before the next time you modify the code (such as adding new features or fix Bug) is a more reasonable and effective.
20.2 The first test
Requirements: Our requirement is that if Question is released in one day, was_published_recently () 方法将会返回
True ,然而现在这个方法在
Question 的
pub_date` field will also return True, later than the current time
Write test code:
from django.test import TestCase
Create your tests here.
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is in the future.
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
Run the code: $ python manage.py test polls
Test Results:
python manage.py test polls
You will findpolls
application in the test code- It found
django.test.TestCase
one of its subclasses - It creates a special database for testing
- It is looking for test methods in a class - A
test
method beginning. - In the
test_was_published_recently_with_future_question
process, it creates apub_date
value of 30 daysQuestion
instance. - Then use the
assertls()
method, we discoveredwas_published_recently()
returnsTrue
, and we expect it to returnFalse
.
Tell us what the test system test sample fails, the test fails and causes the line number of the code is located.
(21) static files (pictures / script / style)
For small projects, in which static files easily, as long as the server can find them on the line. However, in large projects, working static files needed for different applications becomes a bit of trouble. This is the django.contrib.staticfiles
meaning of existence
Created static
folder, create polls
a file folder, and then in the polls
Create a folder named style.css
file. Stylesheet path should be polls/static/polls/style.css
. Because AppDirectoriesFinder
of the presence, you can simply use the order in Django polls/style.css
form reference this file, similar to the way you quote template path.
li a {
color: green;
}
The polls cited index.html
{% load static %}
add pictures
We will create a directory for the presence of the image. In polls/static/polls
Create a directory named images
subdirectories. In this directory, called a put background.gif
picture. In other words, in the catalog polls/static/polls/images/background.jpg
put a picture.
body {
background: white url("images/background.gif") no-repeat;
}
For more information on setting the framework and reference static files doubts and static files guide . Deploy static files describes how to use a static file on the real servers.
(22) the first to write a django application
22.1 polls / admin form defined background, the display order list for the field
from django.contrib import admin
Register your models here.
from .models import Question,Choice
class QuestionAdmin(admin.ModelAdmin):
# fieldsets = [
# ('问题内容', {'fields': ['question_text']}),
# ('发布时间', {'fields': ['pub_data']}),
# ]
# fields = ['pub_data', 'question_text']
list_display = ('question_text', 'pub_data')
admin.site.register(Question, QuestionAdmin)
class ChoiceAdmin(admin.ModelAdmin):
# fields = ['question','choice_text', 'votes']
list_display = ('question','choice_text', 'votes')
admin.site.register(Choice, ChoiceAdmin)
Field filter 22.2
class QuestionAdmin(admin.ModelAdmin):
list_display = ('question_text', 'pub_data')
list_filter = ['pub_data'] # 过滤器
admin.site.register(Question, QuestionAdmin)
22.3 custom background and style of interface
- Open your settings file (
mysite/settings.py
and remember), inTEMPLATES
adding settingDIRS
options: In the
templates
Create a directory named in theadmin
directory, then the default directory where Django template (django/contrib/admin/templates
template files) withinadmin/base_site.html
copied into this directory. Where Django source files? $ Python -c "import django; print (django .__ path__)"Then, replace [in the file with the name of your site
](https://docs.djangoproject.com/zh-hans/2.2/intro/tutorial07/#id1){{ site_header|default:_('Django administration') }}
(curly braces). Upon completion, you should see the following code:
{% block branding %}
Polls Administration
{% endblock %}