Tagged

Django

A collection of 36 posts

Wagtail

Django + Wagtail Secure Key Issue

原有的一个 Django 网站需要集成 Watail,集成之前使用 Python os.urandom(24) 生成的 Secure Key 且使用起来没有异常,就像下面这样: SECRET_KEY = b'L\x132\xb9\xb8k\x8f\xeb#]D\xa7\xcf\xc3\x1fGz\xa3\xc4&\x8a\xd1\xb2\xeb' 但是集成了 Wagtail 以后,程序就没法正常运行。错误结果大概是 Secure Key 无法被转换成 ‘str’。 解决方法:只要删掉密钥前面的字符b就可以了。

Django

Django get previous and next page

新闻页面的页脚需要添加上一篇和下一篇导航,queryset 提供了 get_next_sibling() 和 get_prev_sibling() 方法,直接链到模型查询后面即可。 # 上一篇和下一篇 def get_context(self, request): context = super().get_context(request) if NewsPage.objects.live().get(pk=self.id).get_next_sibling(): context['next'] = NewsPage.objects.live().get(pk=self.id).get_next_sibling() else: context['next'] = False

Django

Django 项目开始前先自定义 User Model

Django 官方文档的自定义身份认证部分有这样一句话: If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. 如果您正在启动一个新项目,强烈建议设置一个自定义用户模型,即使默认的用户模型对您来说已经足够了。 如果是边开发边看文档,等读到这部分时,黄瓜菜都凉了。 项目文档编写自然有它的逻辑,不在文档最开始的时候提出这个建议也是为了不给新手造成困扰。换位思考,如果自己是初学者,连项目和应用的区别还没弄明白,文档入门一上来就告诉你先创建个自定义的用户应用,然后在模型里面继承某个抽象类定义个自定义用户模型,我一定马上把网页关掉。 新 Django 项目 创建好项目,各种配置先做好,配置自定义户用模型要在执行

Django

Django 模型使用 Wagtail Image

Wagtail 封装了理想的图片管理模块,大大减少了网站开发的工作量,在继续编写笔记之前,必须向 Wagtail 的开发者致敬! 绝大多数时候,网站项目都会超越 CMS 的范畴,如果能在普通的 DJango APP 上使用 Wagtial 的图片管理类,那一定是很感人的。 模型 在 Django 模型中,以外键的形式调用 wagtail Image 类。 from django import forms from django.db import models from wagtail.images.models import Image class Product(models.Model): intro = models.CharField( '公司简介', null=

Django

Django 模板 filter 实现字符转列表

用 Django 做表单时候,多选项会按 列表 格式,以字符串的形式记录在数据库: 由于需要用已记录的字段去判断是否给 input 添加 checked 属性,但直接迭代这个项会发现它是以字符串的形式被迭代的,也就是以字符为单位进行迭代,这可不是我们想要的效果。 我想要的是,让这个字段的值是以一个 list() 的形式来使用的。这时候,就需要自定义 django 模板过滤器来实现需求。 创建自定义标签文件 在应用的根目录创建 templatetags 目录,在里面创建自定义标签文件,文件名是未来 {% load file_name %} 使用的,所以可以把自定义标签进行归类,如果没那么多自定义标签,完全可以这样命名 myapp_tags.py,myapp 是应用的名称。使用时候,在模板中 {% load myapp_tags %} 这样加载。 自定义标签 from django

Django

Django DeleteView 不显示 message

Django 的 success_message 基于 form_valid,因为删除视图不包含表单验证,因此 SuccessMessageMixin 在这里不起作用。 解决办法 from django.shortcuts import reverse from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin from django.views.generic.edit import DeleteView from company.models import ProductImage class ProductDelete(LoginRequiredMixin, SuccessMessageMixin, DeleteView): model = ProductImage template_name

Django

Django Generic editing views 笔记

Django 面向网站最常见的 CURD 提供了一系列基于类视图的封装,比如需要做一个创建内容的表单,直接在视图创建继承 CreateView 的类,随后添加路由,配置模板即可。 CreateView from django.shortcuts import reverse from django.views.generic.edit import UpdateView, CreateView from product.models import ProductImage class ProductAdd(CreateView): model = ProductImage fields = '__all__' template_name = 'myapp/product_add.html' def get_success_url(self): return

Django

Django 修改密码视图

参考其他人分享的函数视图的版本,我改写了类视图版本。 Django 提供了修改密码的表单封装,所以自己不用重复造轮子,直接调用就可以。 视图 from django.shortcuts import render, redirect from django.views import View from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth.forms import PasswordChangeForm class ChangePassword(View): def get(self, request): context = dict() context['form']

Django

Django "Cannot drop column 'page_ptr_id': needed in a foreign key

Wagtail 提供的很多功能需要通过外键实现,应用创建的多了类写的多了就免不了将某个模型中的类和其外键类一并删除或改换其他地方。如果使用 sqlite 数据库,执行迁移并没有问题。但生产环境使用 mysql/mariadb 时就会出现标题所示的错误。 django.db.utils.OperationalError: (1829, "Cannot drop column 'page_ptr_id': needed in a foreign key constraint 'home_formfield_page_id_11ee50f3_fk_home_formpage_page_ptr_id' of table `myproject`.`home_formfield`") 解决办法是不要把类和外键类一并删除,而是应该分步执行。先删除外键类,执行一次迁移,

Wagtail

Django/Wagtail debug=False 出现 500 错误

生产环境肯定是要关闭 debug 的,开发环境运行的好好的,可是部署到生产环就给报一个 Error 500 内部服务器错误,debug=True 马上就能正常访问。这个问题有两个原因: 原因一 未配置允许的主机 生产环境配置文件 production.py 中有一行: ALLOWED_HOSTS = ['it.ismy.fun', '.ismy.fun'] 把站点使用的域名填进去。配置以后还是 500错误? 原因二 静态文件问题 生产环境中,Django 是不管静态文件的,所以我们要配置一个静态文件的存储后端。配置好后端,用 ./manage.py collectstatic 将程序中所有静态文件分发到存储后端,这样就一定能访问了。 解决方法:Wagtail/Django 使用 S3-like 对象存储 一个奇葩的问题 我配置了用对象存储作为后端,

Wagtail

Wagtail/Django 使用 S3-like 对象存储

本地开发使用 django 自带的服务器,静态文件直接在项目目录中托管。一旦要往生产环境部署时,就会发现必须为前端静态文件和其他媒体文件配置一个单独的存储后端,Django 说它不管这事儿。 存储后端可以直接在服务器上配置一个静态服务器,也可以直接使用 AWS S3 之类的对象存储,这里主要记录对象存储后端的配置方法。 对于 wagtail 来说,使用对象存储并不能让网站程序完全减负,很多对图片和文档的操作需要先将文件从对象存储取回到服务器的内存中,处理好以后再返回给访问者。Anyway,对象存储可以分担带宽,总之利大于弊。 第一步 安装存储管理相关的包 使用 django-storages 管理存储后端,使用 boto3 实现 s3-like 对象存储的管理。 $ pipenv install django-storages boto3 将包信息写入 requirements.txt 文件: $ pip freeze > requirements.txt 第二步 启用 storages 模块

Django

Django 实现简单的文件上传

前端通过 Dropzone 组件上传文件到后端,因此需要准备一个简易的后端来处理上传请求。 这里创建了一个名为 topic 的 app,在应用目录下创建 urls.py 文件: from django.urls import path from . import views urlpatterns = [ path('upload/', views.image_upload, name='jdd_upload'), ] 在项目 urls.py 中引用: from django.conf.urls import include, url urlpatterns = [ url(r'^topic/', include('topic.urls')), ] 在应用

Django

Django url() 与 path() 的区别

在配置 Django 路由时,经常会看到一些使用 url(),又有一些使用 path(),究竟它们有什么区别,分别适用于于什么情况呢? 其实 url() 是 re_path() 的别名,它俩主要用在需要使用正则表达式的路由配置中。 而 path() 则用于一般情况的路由配置,其性能应该会稍好于另外两者。 Reference How should I choose between url() and path() in Django urls.py file?

Django

Django for 循环计数

碰到一个奇葩的前端设计,下拉列表切换不同的面板,用不同的面板来对同一个单选字段下的项进行分类。比如前3项在第一个 panel,随后的2项在第二个 panel,最后3项在第三个 panel。 这样一来就需要用 for 循环对这个项进行迭代,Django 手册有介绍 {{ forloop.counter }},把它扔进 for 循环里,会帮助计数,从 1 开始,如果想从 0 开始,可以使用 {{ forloop.counter0 }}。 如下,从第8项开始渲染: {% for i in form.topic %} {% if forloop.counter > 7 %} <p> <label for="{{ i.data.

Django

Django Session

Django 启用 Session 需要在配置文件中加载中间件 'django.contrib.sessions.middleware.SessionMiddleware',创建项目时默认是启用的。 这里主要记录一些常规用法: 创建、修改和删除 创建一个名为 greeting 值为 Hi there! 的 session: request.session['greeting'] = 'Hi there!' 将 greeting 的值修改为 Hello: request.session['greeting'] = 'Hello' 删除 greeting: del request.session['greeting'] 在视图中使用 Session 打印全部 session 项 {{ request.session.items }} 打印全部 session

Wagtail

Wagtail 搜索字段为外键时的处理

Wagtail 封装了便利的字段搜索能力,在不做任何设置的情况下,它会默认搜索页面标题,任何需要被搜索的字段都可以直接在模型中进行定义,比如需要额外搜索品牌名称字段: from django.db import models from wagtail.core.models import Page from wagtail.search import index class CompanyPage(Page): brand = models.CharField( '品牌名', blank=False, null=False, max_length=250) search_fields = Page.search_fields + [、 index.SearchField('brand'), ] 索引字段为外键 当需要被搜索的字段为外键时,如果像其他标准字段一样引用,则会报错: FieldError at

Django

Django template 标签和过滤器

实现加法运算 想直接在模板中做形如 {% with number = 1 + 2 %} 的变量计算是不可能的,想让变量实现简单的相加可以通过 add 过滤器实现。 比如:我要构建一个字符串,page.year 变量会打印一个四位数的年份,如果想把它组成 2019-review 这样的字符串,可以这样写: {% slugurl page.year|add:'-review' %} slugurl 是 wagtail 中的一个根据 slug 生成 url 的标签。它与本例要记录的内容无关。 将 int 转换为 string 将数字 5 转换为字符串: {{ 5|stringformat:'i' }}

Wagtail

Wagtail custom default slug 自定义超链接默认值

默认情况下 Wagtail 的 slug(超链接缩略名)会沿用标题,对于中文频道就比较麻烦,因为超链接中有一段中文,从视觉效果和链接长度上来讲都不大科学。 可以通过重写 clean() 方法实现在保存页面之前,覆盖默认的 slug 等项的值: import time from django.utils.text import slugify class NewsPage(Page): title_pic = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) intro = models.CharField('摘要', blank=

Wagtail

Wagtail 子页面排序

与 Wordpress 对 post 和 page 做区分不同,wagtail 视一切为页面。比如一个新闻频道,所有的新闻都是索引页的子页面,它们与关于我们类似的单页面性质完全相同,可能最大的区别就是它们属于不同的父页面。 例如有这样一个索引模型: class NewsIndexPage(Page): # 允许创建子页面类型 subpage_types = ['news.NewsPage'] banner = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) content_panels = Page.content_panels + [ ImageChooserPanel('banner'), ] 如果不做任何设置,在模板中可以通过 page.

Django

Django Template 日期格式化

{{ post.first_published_at | date:"Y-m-d" }} 打印当前时间 一般在页脚版权位会写上当前的年份,如果能自动显示当前年份就省去了每年手动更新的麻烦。特别是忘记更新的时候,那种网站无人维护的既视感对访客影响很大。通过 Django now filter 直接打印当前时间: {% now "Y" %} 格式化参数根据需要设置即可 Reference https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#now How to display the current year in a Django template?

Django

Django migrate rollback 迁移回滚

Django 1.8+ 的版本可以通过以下命令实现回滚到上一个迁移(rollback to previous migrate)。 比如这里要操作的 app 是 news。 查看一个 app 的迁移列表 $ ./manage.py showmigrations news news [X] 0001_initial [X] 0002_auto_20190718_1016 [X] 0003_newsindexpage_banner 撤销最近一次的 migrate 重新执行其前一次提交,即可撤销最新的一个提交: $ ./manage.py migrate news 0002 撤销某个 app 的全部 migrate $ ./manage.py migrate news zero