目录
准备工作
urls.py
models.py
admins.py
views.py
template
静态文件
部署
改进
零碎知识点
null和blank的区别
render与render_response
get_absolute_url

Python-Django

Feb 15, 2017 pm 03:30 PM
django python

准备工作

新建一个Django项目

# 新建一个django项目
$ django-admin startproject mysite
# 新建一个app
$ django-admin startapp blog
登录后复制

项目的结构

├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
登录后复制
# mysite/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog', 
    'markdown2'
]
登录后复制
$ python3 manage.py runserver

$ python manage.py collectstatic
登录后复制

一般在urls.py中配置url,在models.py中配置model,在views.py中配置View。

urls.py

Function views

1. Add an import:  from my_app import views
2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
登录后复制

Class-based views

1. Add an import:  from other_app.views import Home
2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
登录后复制

Including another URLconf

1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
登录后复制
# blog/urls.py

from django.conf.urls import url
from blog import views

urlpatterns = [
    url(r'^blog/$', views.IndexView.as_view(), name='index'),
    url(r'^blog/article/(?P<article_id>\d+)$', views.ArticleDetailView.as_view(), name='detail'),
    url(r'^blog/category/(?P<cate_id>\d+)$', views.CategoryView.as_view(), name='category'),
    url(r'^blog/tag/(?P<tag_id>\d+)$', views.TagView.as_view(), name='tag'),
]
登录后复制

使用(?P<>d+)的形式捕获值给<>中得参数,比如(?Pd+),当访问/blog/article/3时,将会将3捕获给article_id,这个值会传到views.ArticleDetailView。

# mysite/urls.py

from django.conf.urls import url, include
from django.contrib import admin
from blog import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'', include('blog.urls', namespace='blog', app_name='blog'))
]
登录后复制

其中namespace参数为我们指定了命名空间,这说明这个urls.py中的url是blog app下的,这样即使不同的app下有相同url也不会冲突了。

假设用户要访问某篇文章,它会自动解析 blog:detail 这个视图函数对应的 url,并且把 article.pk(文章的主键)传递给detail视图函数,details就是我们在blog/urls.py中指定的name

<a href="{% url &#39;blog:detail&#39; article.pk %}">{{ article.title }}</a>
登录后复制

如果要访问某个目录

<a href="{% url &#39;blog:category&#39; category.pk %}">{{ category.name }}</a>
登录后复制

models.py

django.db.models是orm框架的基础,在blog/models.py中新建Article, Category, Tag三个model。

class Article(models.Model):
    STATUS_CHOICES = (
        ('d', 'Draft'),
        ('p', 'Published'),
    )
    
    # 仍然使用默认的 objects 作为 manager 的名字
    objects = ArticleManager()

    title = models.CharField('标题', max_length=70)
    body = models.TextField('正文')
    created_time = models.DateTimeField('创建时间', auto_now_add=True)
    last_modified_time = models.DateTimeField('修改时间', auto_now=True)
    status = models.CharField('文章状态', max_length=1, choices=STATUS_CHOICES)
    # blank和null要同时设置为null,详情参考官方文档
    abstract = models.CharField('摘要', max_length=54, blank=True, null=True, 
                                help_text="可选,如若为空将摘取正文的前54个字符")
    views = models.PositiveIntegerField('浏览量', default=0)
    likes = models.PositiveIntegerField('点赞数', default=0)
    topped = models.BooleanField('置顶', default=False)
    
    category = models.ForeignKey('Category', verbose_name='分类', null=True, on_delete=models.SET_NULL)
    tags = models.ManyToManyField('Tag', verbose_name='标签集合', blank=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-last_modified_time']

    # 新增 get_absolute_url 方法
    def get_absolute_url(self):
        # 这里 reverse 解析 blog:detail 视图函数对应的 url
        return reverse('blog:detail', kwargs={'article_id': self.pk})
登录后复制

Django给我们提供了很多有用的字段,比如上面提到的CharFiled, TestField, DateTimeFiled等等,详情请参考官方文档。

Django中的一对多是在一中进行设置,这里对应于文章的分类,ForeignKey即数据库中的外键。on_delete=models.SET_NULL表示删除某个分类(category)后该分类下所有的Article的外键设为null(空),所以我们同时设置了null=True。多对多就不同,两边都要进行配置。详情请参考官方文档。

class Category(models.Model):
    name = models.CharField('类名', max_length=20)
    created_time = models.DateTimeField('创建时间', auto_now_add=True)
    last_modified_time = models.DateTimeField('修改时间', auto_now=True)

    def __str__(self):
        return self.name
登录后复制
class Tag(models.Model):
    name = models.CharField('标签名', max_length=20)
    created_time = models.DateTimeField('创建时间', auto_now_add=True)
    last_modified_time = models.DateTimeField('修改时间', auto_now=True)

    def __str__(self):
        return self.name
登录后复制

评论功能的实现

class BlogComment(models.Model):
    user_name = models.CharField('评论者名字', max_length=100)
    user_email = models.EmailField('评论者邮箱', max_length=255)
    body = models.TextField('评论内容')
    created_time = models.DateTimeField('评论发表时间', auto_now_add=True)
    article = models.ForeignKey('Article', verbose_name='评论所属文章', on_delete=models.CASCADE)

    def __str__(self):
        return self.body[:20]
登录后复制
class ArticleManage(models.Manager):
    """
    继承自默认的 Manager ,为其添加一个自定义的 archive 方法
    """
    def archive(self):
        date_list = Article.objects.datetimes('created_time', 'month', order='DESC')
        # 获取到降序排列的精确到月份且已去重的文章发表时间列表
        # 并把列表转为一个字典,字典的键为年份,值为该年份下对应的月份列表
        date_dict = defaultdict(list)
        for d in date_list:
            date_dict[d.year].append(d.month)
        # 模板不支持defaultdict,因此我们把它转换成一个二级列表,由于字典转换后无序,因此重新降序排序
        return sorted(date_dict.items(), reverse=True)
登录后复制

我们首先要在project_name/settings.py中配置好相应的配置文件

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'DB_NAME',
        'USER': 'DB_USER',
        'PASSWORD': 'DB_PASSWORD',
        'HOST': 'localhost',   # Or an IP Address that your DB is hosted on
        'PORT': '3306',
    }
}
登录后复制

定义完毕后,我们执行下面的命令就在数据库中可以生成相应的数据表:

$ python manage.py makemigrations

$ python manage.py migrate
登录后复制

admins.py

参考Mozila的教程以及结合官方文档。

views.py

下面要使用markdown2,所以在INSTALLED_APP里面要添加markdown2,不过这个mardown解析非常的不好,并且弄完还要去下载相应的markdown的css文件,有个专门的网站。

from blog.models import Article, Tag, Category
from django.views.generic import ListView, DetailView
import markdown2

class IndexView(ListView):
    # template_name属性用于指定使用哪个模板进行渲染
    template_name = "blog/index.html"

    # context_object_name属性用于给上下文变量取名(在模板中使用该名字)
    context_object_name = "article_list"

    def get_queryset(self):
        article_list = Article.objects.filter(status='p')
        for article in article_list:
            article.body = markdown2.markdown(article.body, )
        return article_list

    def get_context_data(self, **kwargs):
        kwargs['category_list'] = Category.objects.all().order_by('name')
        # 调用 archive 方法,把获取的时间列表插入到 context 上下文中以便在模板中渲染
        kwargs['date_archive'] = Article.objects.archive()
        kwargs['tag_list'] = Tag.objects.all().order_by('name')
        return super(IndexView, self).get_context_data(**kwargs)
登录后复制

上面因为我们要进行markdown处理,所以重新自定义了get_queryset,如果不要进行相应的处理,直接制定model就行了,get_context_data可以添加一些额外的字段,比如以后我们要在首页的侧边栏显示目录和标签,所以这里要添加一个category_listtag_list

class ArticleDetailView(DetailView):
    model = Article
    template_name = "blog/detail.html"
    context_object_name = "article"
    # pk_url_kwarg会自动和model中相应的主键对应,aritlce_id就是下面配置的URLCONF
    pk_url_kwarg = 'article_id'

    # 为了让文章以markdown形式展现,我们重写get_object()方法
    def get_object(self):
        obj = super(ArticleDetailView, self).get_object()
        obj.body = markdown2.markdown(obj.body)
        return obj
        
    # 新增 form 到 context
    def get_context_data(self, **kwargs):
        kwargs['comment_list'] = self.object.blogcomment_set.all()
        kwargs['form'] = BlogCommentForm()
        return super(ArticleDetailView, self).get_context_data(**kwargs)
登录后复制
class CategoryView(ListView):
    template_name = "blog/index.html"
    context_object_name = "article_list"
    
    def get_queryset(self):
        # url里的cate_id传递给CategoryView,传递的参数在kwargs属性中获取
        article_list = Article.objects.filter(category=self.kwargs['cate_id'],status='p')
        for article in article_list:
            article.body = markdown2.markdown(article.body, )
        return article_list

    def get_context_data(self, **kwargs):
        # 增加一个category_list,用于在页面显示所有分类,按照名字排序
        kwargs['category_list'] = Category.objects.all().order_by('name')
        return super(CategoryView, self).get_context_data(**kwargs)
登录后复制
class TagView(ListView):
    template_name = "blog/index.html"
    context_object_name = "article_list"

    def get_queryset(self):
        """
        根据指定的标签获取该标签下的全部文章
        """
        article_list = Article.objects.filter(tags=self.kwargs['tag_id'], status='p')
        for article in article_list:
            article.body = markdown2.markdown(article.body, extras=['fenced-code-blocks'], )
        return article_list

    def get_context_data(self, **kwargs):
        kwargs['tag_list'] = Tag.objects.all().order_by('name')
        return super(TagView, self).get_context_data(**kwargs)
登录后复制
from django.views.generic.edit import FormView

class CommentPostView(FormView):
    form_class = BlogCommentForm
    template_name = 'blog/detail.html' 

    def form_valid(self, form):
        target_article = get_object_or_404(Article, pk=self.kwargs['article_id'])
        # 调用ModelForm的save方法保存评论,设置commit=False则先不保存到数据库,
        # 而是返回生成的comment实例,直到真正调用save方法时才保存到数据库。
        comment = form.save(commit=False)
        # 把评论和文章关联
        comment.article = target_article
        comment.save()
        # 评论生成成功,重定向到被评论的文章页面,get_absolute_url 请看下面的讲解。
        self.success_url = target_article.get_absolute_url()
        return HttpResponseRedirect(self.success_url)

    def form_invalid(self, form):
        target_article = get_object_or_404(Article, pk=self.kwargs['article_id'])

        # 不保存评论,回到原来提交评论的文章详情页面
        return render(self.request, 'blog/detail.html', {
            'form': form,
            'article': target_article,
            'comment_list': target_article.blogcomment_set.all(),
        })
登录后复制

template

{% for %}循环标签,{% if %}判断标签. {{ variable }}是一些非常常用的标签

在模板文件中我们可以这样使用,views.py中已经指定了context_object_name = "article_list",并且已经在get_queryset()中进行了markdown处理

{% for article in article_list %}
    {{article.title}}
登录后复制

通常都会设置一个通用的父模板:

{% extends "base_generic.html" %}

{% block content %}
...
{% endblock %}
登录后复制

好像要这么这么设置:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'blog/templates')]
        ,
        'APP_DIRS': True,
...
]
登录后复制

静态文件

由于源代码丢失,具体情况记得不太清晰,静态文件路径要设置好,如果js文件加载异常,可能是加载顺序的问题。

base_generic.html大概就是下面这样的格式:

<!DOCTYPE html>
{% load staticfiles %}
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Myblog</title>
    <link rel="stylesheet" href="{% static &#39;lib/css/bootstrap.min.css&#39; %}">
    <link rel="stylesheet" href="{% static &#39;blog/css/style.css&#39; %}">
    <link rel="stylesheet" href="{% static &#39;blog/css/pygments/github.css&#39; %}">
</head>
...
登录后复制

下面这样设置貌似有点问题:

# mysite/settings.py
STATIC_URL = '/static/'
STATICFILES = os.path.join(BASE_DIR, 'blog/static')
登录后复制

具体参考官方文档

部署

使用uwsgi+nginx

/etc/nginx/sites-available/mysite.conf,blog是app名字,static文件放在了下面,建议直接放在mysite下面,template也是一样:

server {
    listen 80;

    location /static/ {
        alias /home/omrsf/mysite/blog/static/;
    }

    location / {
        uwsgi_pass 127.0.0.1:8001;
        include     /etc/nginx/uwsgi_params;
    }
}
登录后复制

uwsgi -i uwsgi.ini来启动uwsgi进程,结合nohup &

[uwsgi]
socket = 127.0.0.1:8001
chdir=/home/ormsf/mysite/
wsgi-file = mysite/wsgi.py

processes = 2
threads = 4

chmod-socket = 664
登录后复制

改进

目前文章是直接在admin.py中注册model,然后去admin后台发布的,可以做成api接口,做一个在线的编辑器。增加基本的用户认证功能。

零碎知识点

null和blank的区别

  • null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空。

  • blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填,比如 admin 界面下增加 model 一条记录的时候。直观的看到就是该字段不是粗体。

render与render_response

优先采用render。

get_absolute_url

model有一个get_absolute_url,它可以与reverse结合起来。

更多Python-Django相关文章请关注PHP中文网!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何利用Debian Apache日志提升网站性能 如何利用Debian Apache日志提升网站性能 Apr 12, 2025 pm 11:36 PM

本文将阐述如何通过分析Debian系统下的Apache日志来提升网站性能。一、日志分析基础Apache日志记录了所有HTTP请求的详细信息,包括IP地址、时间戳、请求URL、HTTP方法和响应代码等。在Debian系统中,这些日志通常位于/var/log/apache2/access.log和/var/log/apache2/error.log目录下。理解日志结构是有效分析的第一步。二、日志分析工具您可以使用多种工具分析Apache日志:命令行工具:grep、awk、sed等命令行工具可

Python:游戏,Guis等 Python:游戏,Guis等 Apr 13, 2025 am 12:14 AM

Python在游戏和GUI开发中表现出色。1)游戏开发使用Pygame,提供绘图、音频等功能,适合创建2D游戏。2)GUI开发可选择Tkinter或PyQt,Tkinter简单易用,PyQt功能丰富,适合专业开发。

PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

debian readdir如何与其他工具集成 debian readdir如何与其他工具集成 Apr 13, 2025 am 09:42 AM

Debian系统中的readdir函数是用于读取目录内容的系统调用,常用于C语言编程。本文将介绍如何将readdir与其他工具集成,以增强其功能。方法一:C语言程序与管道结合首先,编写一个C程序调用readdir函数并输出结果:#include#include#includeintmain(intargc,char*argv[]){DIR*dir;structdirent*entry;if(argc!=2){

Python和时间:充分利用您的学习时间 Python和时间:充分利用您的学习时间 Apr 14, 2025 am 12:02 AM

要在有限的时间内最大化学习Python的效率,可以使用Python的datetime、time和schedule模块。1.datetime模块用于记录和规划学习时间。2.time模块帮助设置学习和休息时间。3.schedule模块自动化安排每周学习任务。

Nginx SSL证书更新Debian教程 Nginx SSL证书更新Debian教程 Apr 13, 2025 am 07:21 AM

本文将指导您如何在Debian系统上更新NginxSSL证书。第一步:安装Certbot首先,请确保您的系统已安装certbot和python3-certbot-nginx包。若未安装,请执行以下命令:sudoapt-getupdatesudoapt-getinstallcertbotpython3-certbot-nginx第二步:获取并配置证书使用certbot命令获取Let'sEncrypt证书并配置Nginx:sudocertbot--nginx按照提示选

Debian OpenSSL如何配置HTTPS服务器 Debian OpenSSL如何配置HTTPS服务器 Apr 13, 2025 am 11:03 AM

在Debian系统上配置HTTPS服务器涉及几个步骤,包括安装必要的软件、生成SSL证书、配置Web服务器(如Apache或Nginx)以使用SSL证书。以下是一个基本的指南,假设你使用的是ApacheWeb服务器。1.安装必要的软件首先,确保你的系统是最新的,并安装Apache和OpenSSL:sudoaptupdatesudoaptupgradesudoaptinsta

Debian上GitLab的插件开发指南 Debian上GitLab的插件开发指南 Apr 13, 2025 am 08:24 AM

在Debian上开发GitLab插件需要一些特定的步骤和知识。以下是一个基本的指南,帮助你开始这个过程。安装GitLab首先,你需要在Debian系统上安装GitLab。可以参考GitLab的官方安装手册。获取API访问令牌在进行API集成之前,首先需要获取GitLab的API访问令牌。打开GitLab仪表盘,在用户设置中找到“AccessTokens”选项,生成一个新的访问令牌。将生成的

See all articles