美文网首页
第一章Django by example

第一章Django by example

作者: StewieK | 来源:发表于2017-10-17 10:33 被阅读106次

    项目前准备

    1.创建env环境,virtualenv --no-site-packages 文件夹名
    2.激活virtualenv中的python版本,source 文件夹名/bin/activate
    3.在激活状态下,安装django 
    

    第一个Blog项目

    1.    djangoadmin startproject mysite       --创建mysite项目
    2.    cd mysite                             --切换至项目文件夹
    3.    python3 manage.py startapp blog       --创建blog应用
    4.    python3 manage.py migrate             --数据库创建初始表
    5.    python3 manage.py runserver 或
          python3 manage.py runserver  -- settings=mysite.settings     --启动测试服务器
    

    在应用文件夹下的models中创建

    from django.contrib.auth.models import User  # 导入django.扩展.认证.模型中的User
    from django.db import models  # 导入django.数据库中的models模型
    from django.utils import timezone  # 导入django.实用工具中的timezone,需要安装pip install pytz
    
    
    # Create your models here.
    
    class Post(models.Model):
        STATUS_CHOICES = (
            ('draft', 'Draft'),
            ('published', 'Published'),
        )
        title = models.CharField(max_length=250)
        slug = models.SlugField(max_length=250, unique_for_date='publish')
        body = models.TextField()
        author = models.ForeignKey(User, related_name='blog_posts')
        publish = models.DateTimeField(default=timezone.now)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
        objects = models.Manager()  # The default manager.
        published = PublishedManager()  # Our custom manager.自定义管理器
    
        class Meta:
            ordering = ('-publish',)  # 查询数据库时候将以publish的倒序排序
    
        def __str__(self):
            return self.title  # str()方法是当前对象默认的可读表现。Django将会在很多地方用到它例如管理站点中。
    
    
    # ------------ 添加自定义models manager模型管理器-----------------
    
    要放在Post之前
    class PublishedManager(models.Manager):
        def get_queryset(self):
            return super(PublishedManager, self).get_queryset().filter(status='published')
    # -------------------------------------------------------------
    

    在应用文件夹下admin中注册

    from django.contrib import admin
    
    from .models import Post
    
    
    # Register your models here.
    class PostAdmin(admin.ModelAdmin):
        list_display = ('title', 'slug', 'author', 'publish',
                        'status')  # 在管理站点中的列表显示
        list_filter = ('status', 'created', 'publish', 'author')  # 过滤显示
        search_fields = ('title', 'body')  # 搜索显示
        prepopulated_fields = {'slug': ('title',)}  # slug自动填充,在填写title的时候,slug会自动填充为title内容
        raw_id_fields = ('author',)  # 显示成为搜索控件,以id形式
        date_hierarchy = 'publish'  # 日期层次结构
        ordering = ['status', 'publish']  # admin管理界面按列表中的内容排序
    
    
    admin.site.register(Post, PostAdmin)  # 注册models中的模型,PostAdmin为个性化定制
    

    创建与迁移数据表

    1.python3 manage.py makemigrations
    2.python3 manage.py migrate
    

    部分settings设置

    TIME_ZONE = 'Asia/Shanghai'
    Django1.9以后language code 'zh-cn'就被丢弃了,使用'zh-hans'代替
    

    使用查询集(QuerySet)

    python3 manage.py shell进入shell
    
    from django.contrib.auth.models import User
    from blog.models import Post
    user = User.objects.get(username='用户名')
    post = Post.objects.create(author=user,title='内容',body='内容',slug='内容')
    #使用create不需要使用post.save(),直接进行数据库操作
    #-----------------------------------------------------------------------------
    post = Post(title='Another post', slug='another-post', body='Postbody.', \
    author=user)#这样使用必须使用post.save(),否则只保存在内存中,没有插入数据库
    post.save()#对数据库执行操作
    
    #更新对象字段
    post.title='改变内容'
    post.save()
    
    post.delete()#删除对象
    -------------------------------------------------------------------------------
    

    使用filter()过滤、exclude()排除、order_by()排序

    Post.objects.filter(publish__year=2015)#返回在2015年的对象
    
    #返回2015年且author是'admin'的对象
    Post.objects.filter(publish__year=2015, author__username='admin')
    或Post.objects.filter(publish__year=2015).filter(author__username='admin')
    
    #返回所有2015年发布的帖子但是这些帖子的题目开头不能是Why
    Post.objects.filter(publish__year=2015).exclude(title__startswith='Why')
    
    #返回所有且对title字段升序排序
    Post.objects.order_by('title')
    #返回所有且对title字段倒序排序
    Post.objects.order_by('-title')
    

    查询集(QuerySet)什么时候会执行

    只要你喜欢,你可以连接许多的过滤给查询集(QuerySet)而且不会立马在数据库中执行直到这个查询集(QuerySet)被执行。查询集(QuerySet)只有在以下情况中才会执行:

    • 在你第一次迭代它们的时候
    • 当你对它们的实例进行切片:例如Post.objects.all()[:3]
    • 当你对它们进行了打包或缓存
    • 当你对它们调用了repr()或len()方法
    • 当你明确的对它们调用了list()方法
    • 当你在一个声明中测试它,例如bool(), or, and, or if

    创建templates(模板文件夹)与static(静态文件夹)

    • 默认创建在应用文件夹下,自定义需要在DIRS列表中定义,BASE_DIR是指mysite项目的绝对路径,可以使用完整路径
        TEMPLATES = [
        {    
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],#如果需要自定定义位置,需要在此处列表内加入
            'APP_DIRS': True,#默认在app文件夹内
            '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',
                ],
            },
        },
    ]
    
    STATIC_URL = '/static/'
     
    # 当运行 python manage.py collectstatic 的时候
    # STATIC_ROOT 文件夹 是用来将所有STATICFILES_DIRS中所有文件夹中的文件,以及各app中static中的文件都复制过来
    # 把这些文件放到一起是为了用apache等部署的时候更方便
    STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
     
    # 其它 存放静态文件的文件夹,可以用来存放项目中公用的静态文件,里面不能包含 STATIC_ROOT
    # 如果不想用 STATICFILES_DIRS 可以不用,都放在 app 里的 static 中也可以
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, "common_static"),
        '/path/to/others/static/',  # 用不到的时候可以不写这一行
    )
     
    # 这个是默认设置,Django 默认会在 STATICFILES_DIRS中的文件夹 和 各app下的static文件夹中找文件
    # 注意有先后顺序,找到了就不再继续找了
    STATICFILES_FINDERS = (
        "django.contrib.staticfiles.finders.FileSystemFinder",
        "django.contrib.staticfiles.finders.AppDirectoriesFinder"
    )
    

    编辑视图文件views

    from django.shortcuts import render, get_object_or_404  # 从django.快捷工具中导入render,get_object_or_404
    
    from .models import Post  # 从模型中导入Post
    
    
    # Create your views here.
    def post_list(request):
        posts = Post.objects.all()  # 提取实例Post
        return render(request, 'blog/post/list.html', {'posts': posts})  # 渲染至list.html,给html文件posts对象
    
    
    def post_detail(request, year, month, day, post):  # year,month,day,post等参数是从urls文件中获取
        post = get_object_or_404(Post, slug=post,
                                 status='draft',
                                 publish__year=year,
                                 publish__month=month,
                                 publish__day=day)  # 与Post.objects.get()方法相似,get_object_or_404获取不到对象会返回404
    
        return render(request, 'blog/post/detail.html', {'post': post})
    

    为视图添加URL模式

    在APP的文件夹下创建urls文件,惯例

    from django.conf.urls import url
    
    from . import views
    
    urlpatterns = [
        url(r'^$', views.post_list, name='post_list'),
        url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',
            views.post_detail,
            name='post_detail'),
    ]
    
    • year:需要四位数
    • month:需要两位数。不及两位数,开头带上0,比如 01,02
    • day:需要两位数。不及两位数开头带上0
    • post:可以由单词和连字符组成

    在项目urls文件中(mysite/mysite/urls.py)中导入APP的urls文件

    from django.conf.urls import include, url
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', include(admin.site.urls)), 
        url(r'^blog/', include('blog.urls',
            namespace='blog',
            app_name='blog')),
    ]
    

    模型(models)的标准URLs

    在models中添加生成url的代码

    from django.core.urlresolvers import reverse#从django.核心.解析器中导入reverse
    Class Post(models.Model):
        # ...
        def get_absolute_url(self):
            return reverse('blog:post_detail',
                            args=[self.publish.year,
                                  self.publish.strftime('%m'),
                                  self.publish.strftime('%d'),
                                  self.slug])
    我们通过使用strftime()方法来保证个位数的月份和日期需要带上0来构建URL,也就是01,02,03,对象的get_absolute_url方法,会reverse反向的去找urls的blog空间中的post_detail的urls,根据urls会生成一个标准的url(http://127.0.0.1:8000/blog/YEAR/MONTH/DAY),然后url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',views.post_detail,name='post_detail')会处理,然后(?P<year>)会有变量year=VALUE,urls中写的views文件处理,渲染。
    

    html文件,模板标签语言

    文档位置(https://docs.djangoproject.com/en/1.8/)

    templates/
        blog/
            base.html
            post/
                list.html
                detail.html
    

    base为基础部分,list.html,detail.html扩展
    常用:

    • {% load staticfiles %}放置顶端,导入静态文件

    • {% static "css/文件.css" %} 以static文件夹为根,相对路径

    • {% for post in posts %}
      {{post.filed}}
      {{post.get_absolute_url}}调用models中的get_absolute_url方法,生成标准url
      {% end for %}

    • {% block content %} 在base.html中设定的填充区域,填充内容可写在其他html文件中
      {% endblock %}

    • {% extends "blog/base.html" %}继承blog/base.html 模板(template)。然后content区块(blocks)中填充内容。

    • {{ post.body|truncatewords:30|linebreaks }} truncatewords用来缩短内容限制在一定的字数内,linebreaks用来转换内容中的换行符为HTML的换行符。

    • {% include "pagination.html" with page=posts %} 导入 templates下pagination.html(相对路径), 且pagination中的变量page=posts

    分页 使用django内置的paganitor来完成

    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger   # 导入django.核心.分页处理中的分页器,空页,不是整数页
        def post_list(request):
        object_list = Post.objects.all()
        paginator = Paginator(object_list, 3)#每页显示3个对象
        page = request.GET.get('page')#获取到页码
        try:
            posts = paginator.page(page)
        except PageNotAnInteger:#如果页码不是一个整数,显示第一页
            posts = paginator.page(1)
        except EmptyPage:#如果页码是整数但是不存在,显示最大的页
            posts = paginator.page(paginator.num_pages)
    
        return render(request, 'blog/post/list.html', {'page': page, 'posts': posts}) 
    
    

    以上代码工作流程:
    1、打开主页-->127.0.0.1:8000/blog被urls.py中定义的规则捕获-->交由定义的views中的函数处理
    2、paginator=Paginator(object_list,3),每页显示3个对象,paginator为分页处理对象:常用方法有:

    paginator.count #一共有多少个对象
    paginator.num_pages#最大页数
    paginator.page(页码)#页码的对象
    

    3、page=request.Get.get('page'),主页没有page参数,get的结果为None,所以page不是一个整数,posts=paginator.page(1)#返回一个Page类对象

    Page对象常用方法,详细使用看源码,Page对象使用.paginator方法转回Paginator对象
        def has_next(self):
            return self.number < self.paginator.num_pages
    
        def has_previous(self):
            return self.number > 1
    
        def has_other_pages(self):
            return self.has_previous() or self.has_next()
    
        def next_page_number(self):
            return self.paginator.validate_number(self.number + 1)
    
        def previous_page_number(self):
            return self.paginator.validate_number(self.number - 1)
    
        def start_index(self):
            """
            Returns the 1-based index of the first object on this page,
            relative to total objects in the paginator.
            """
            # Special case, return zero if no items.
            if self.paginator.count == 0:
                return 0
            return (self.paginator.per_page * (self.number - 1)) + 1
    
        def end_index(self):
            """
            Returns the 1-based index of the last object on this page,
            relative to total objects found (hits).
            """
            # Special case for the last page because there can be orphans.
            if self.number == self.paginator.num_pages:
                return self.paginator.count
            return self.number * self.paginator.per_page
    

    4、进行render,显示页面

    使用基于类的视图(views)简介

    编辑你的blog应用下的views.py文件,如下所示:

    from django.views.generic import ListView  # 从django.视图.公共 导入ListView
    class PostListView(ListView):
        queryset = Post.objects.all()  # 使用一个特定的查询集(QuerySet)代替取回所有的对象。代替定义一个queryset属性,我们可以指定model = Post然后Django将会构建Post.objects.all() 查询集(QuerySet)给我们。
        context_object_name = 'posts'  #使用环境变量posts给查询结果。如果我们不指定任意的context_object_name默认的变量将会是object_list。
        paginate_by = 3  #对结果进行分页处理每页只显示3个对象。
        template_name = 'blog/post/list.html'  #使用定制的模板(template)来渲染页面。如果我们不设置默认的模板(template),ListView将会使用blog/post_list.html。
    
    
     在urls文件中,我们要调用views.PostlistView.as_view()
    

    为了保持分页处理能工作,我们必须将正确的页面对象传递给模板(tempalte)。Django的ListView通过叫做page_obj的变量来传递被选择的页面,所以你必须编辑你的post_list_html模板(template)去包含使用了正确的变量的分页处理,如下所示:

    {% include "pagination.html" with page=page_obj %}
    

    学习来源于夜夜月翻译的django by example

    相关文章

      网友评论

          本文标题:第一章Django by example

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