美文网首页
django复习笔记(Part1-Part7)

django复习笔记(Part1-Part7)

作者: __Cool | 来源:发表于2017-12-31 20:52 被阅读80次

对 django 官网 First steps 中 7 个入门教程的复习,复习时 django 版本为 1.11。

tutorial01

1、每一个新建的 app 都应再新建一个 urls.py 文件, 管理其目录下的 views.py,在 mysite/urls.py 文件中使用 include() 方法引用 app 里的 urls;

2、urls.py 文件里的 url() 方法可以传四个参数,两个为必须,两个可选:

四个参数
url() argument:regex 正则表达式(必须)
url() argument:view views.py 中的方法(必须)
url() argument:kwargs 可以传入views.py 中的方法的字典(可选)
url() argument:name 用于给 html 页面的链接命名(可选)

tutorial02

1、models.py 可以定义任何数据模型,模型之中可以定义自己的方法或者官方自带的方法,在用此模型的时候可以调用这些添加的方法,方面理解:

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):  # 自带方法
        return self.question_text

    def was_published_recently(self): # 自定义方法
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

2、每次修改 models.py 里的数据模型,需要运行两个命令:
python manage.py makemigrations polls 迁移改变
python manage.py migrate 应用到数据库
其他命令:
python manage.py sqlmigrate polls 0001 查看此次迁移 sql 语法python manage.py shell 在命令行里调试数据模型​

tutorial03

1、在 urls.py 中,url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),其中用括号括器的(?P<question_id>[0-9]+)会做为参数传给 views.detail这个函数,这个函数也要接受这个参数做下一步处理,可以去掉?P<question_id>,这只是为了起说明作用和提前命名,也可以在 views.detail 方法中命名;

2、views.py 中,用get_object_or_404()函数代替try···except更好,在找不到相关数据时 Django 会自动引起 Http404 错误:

# 用 try···except 查询数据
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})

# 用 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})

3、模板中使用 url,尽量不要硬编码,<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>这样的硬编码在改动 urls.py 会很费劲,正确方法是用命名空间,在多个 app 中,可能出现很多同名的 name,这很难记忆,为每一个 app 设置一个 app_name,在搭配url(r'^$', views.index, name='index')中的name,即可在改变 url 路径时不必一改全改,也方便记忆和使用:

# app/urls.py
app_name = 'polls'   # 在每一个 app 的 urls.py 下设置
urlpatterns = [
    url(r'^$', views.index, name='index'),
]
# templates/name.html
<!-- 硬编码方式 -->
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> 

<!-- 更好的编码方式 -->
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> 

tutorial04

1、表单提交,如某项数据需要+1,多人同时提交时,可能会出现数据丢失,通常的代码将这个值从数据库取出来赋值给一个变量,然后执行+1操作,然后再将这个+1后的值保存会数据库,这就可能会出现数据遗漏,更有效的做法是使用 F() 函数,这个函数对数据库直接进行+1操作,而不用通过变量赋值存储:

# 有可能会出现数据遗漏的代码操作,有 Question和Choice 模型
selected_choice = question.choice_set.get(pk=request.POST['choice'])
selected_choice.votes += 1
selected_choice.save()

# 更有效的数据+1操作方法,使用 F() 函数
Choice.objects.filter(votes='hello').update(votes=F('votes')+1)

2、类的通用视图,Less code is better。在 views.py 中,初学 django 时直接用了很多函数来处理每个模板和数据,这种方法也可行,但 django 提供了通用视图使代码更简洁更友好;

# urls.py     通用视图默认变量为pk,所以使用pk
from django.views.generic import TemplateView
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
    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'),
    url(r'^about/$', TemplateView.as_view(template_name="about.html")),# 没有数据查询时可以直接返回模板,这是一种简写方式
]
# views.py
def index():   # 普通函数,与通用视图对比
     latest_question_list = Question.objects.order_by('-pub_date')[:5]
     context = {
         'latest_question_list': latest_question_list,
     }
     return render(request, 'polls/index.html', context)

class IndexView(generic.ListView): #通用视图
    template_name = 'polls/index.html' #指定渲染的模板
    context_object_name = 'latest_question_list' #模板中的变量名,类似 context 上下文 
    def get_queryset(self): # 重写 ListView 方法,查询数据
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]
      
class DetailView(generic.DetailView):# DetailView
    model = Question   # 指定要查询的数据模型
    template_name = 'polls/detail.html' # 指定渲染模板

    
class ResultsView(generic.DetailView):
    model = Question 
    template_name = 'polls/results.html

通用视图除了可以查询指定模型、渲染指定模板外(像上面那样,使用指定参数),还可以添加额外的上下文(也就是context),只需重写 get_context_data() 方法:

class PublisherDetail(DetailView):
    model = Publisher
    def get_context_data(self, **kwargs):  
           context = super(PublisherDetail, self).get_context_data(**kwargs)
          # Add in a QuerySet of all the books
           context['book_list'] = Book.objects.all()
           return context
常用字段解释
context_object_name 指定模板内的变量名,默认为 object_list
model 要查询的模型名称 (简写)
query 是上面的完全写法 ,不一定是 all(),也可以是其他,filter() 等
template_name 指定渲染哪一个模板
常用方法解释
get_queryset(self) 模型查询处理
get_context_data(self, **kwargs) 添加额外上下文

tutorial05

1、自动化测试可以发现工程中隐藏的 bug,可以优化代码、保证项目的安全。在每个 app 下都有一个 tests.py 文件用来测试所在 app 是否有 bug,测试方法以 test 开头类以 Tests 结尾

# app/tests.py
import datetime
from django.test import TestCase # 用于测试的工具
from django.urls import reverse
from django.utils import timezone
from .models import Question

class QuestionModelTests(TestCase):
    def test_was_published_recently_with_future_question(self):
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)
        
class QuestionIndexViewTests(TestCase):
    def test_no_questions(self):
        response = self.client.get(reverse('polls:index'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'no polls are available')
        self.assertQuerysetEqual(response.context['latest_question_list'], [])

    def test_past_question(self):
        create_question(question_text='Past question.', days=-30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_question_list'],
            ['<Question: Past question.>']
        )
断言介绍
assertIs 判断真假
assertEqual 判断是否相等
assertContains 内容是否包含在内
assertQuerysetEqual Queryset是否相等

tutorial06

1、添加静态文件支持,根目录下新建 static 文件夹管理 css、js、image 资源,在 settings.py 文件中设置 STATIC_URLSTATICFILES_DIRS,django 会自动搜寻 INSTALLED_APPS 下的 app 并找到 static 文件夹:

# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")
]

编写 css 文件:

/* style.css */
li a {
    color: green;
}
body {
    background: white url("images/background.gif") no-repeat right bottom;
}

html 中引用:

{# index.html #}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />

tutorial07

1、后台管理优化,可以在后台帮助数据模型显示详情信息:

字段解释
fields fields = ['pub_date', 'question_text'] 设置模型中字段的顺序及是否显示
fieldsets fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date']}), ] 将模型中的每个字段分栏
inlines inlines = [ChoiceInline] 将有关联的模型引入,可直接操作该引入模型
list_display list_display = ('question_text', 'pub_date') 模型列表详情
search_fields search_fields = ['question_text'] 添加后台对指定字段的搜索功能

相关文章

网友评论

      本文标题:django复习笔记(Part1-Part7)

      本文链接:https://www.haomeiwen.com/subject/zawagxtx.html