文章目录
1. 配置路由:include
urlpatterns = [
path('admin/', admin.site.urls),
path('article/', include('article.urls', namespace='article')),
path('userprofile/', include('userprofile.urls', namespace='userprofile')),
]
错误写法:path('userprofile/', include('userprofile.urls'), namespace='userprofile'),
,_path() 中多了个参数,namespace 应该在 include 中。
报错:
File "D:\django_learning\blog_project\blog_project\urls.py", line 22, in <module>
path('userprofile/', include('userprofile.urls'), namespace='userprofile'),
TypeError: _path() got an unexpected keyword argument 'namespace'
2. forms 表单类字段 fields
from django import forms
from django.contrib.auth.models import User
class UserRegisterForm(forms.ModelForm): # 对数据库进行操作的表单应继承forms.ModelForm
# 复写 User 的密码
password = forms.CharField()
password2 = forms.CharField()
class Meta:
model = User
field = ('username', 'email')
Django项目中某 app 的 forms.py 段代码如上,执行时报错如下:
File "D:\django_learning\blog_project\userprofile\urls.py", line 8, in <module>
from userprofile import views
File "D:\django_learning\blog_project\userprofile\views.py", line 5, in <module>
from userprofile.forms import UserLoginForm, UserRegisterForm
File "D:\django_learning\blog_project\userprofile\forms.py", line 17, in <module>
class UserRegisterForm(forms.ModelForm): # 对数据库进行操作的表单应继承forms.ModelForm
File "D:\env\lib\site-packages\django\forms\models.py", line 243, in __new__
"needs updating." % name
django.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or
the 'exclude' attribute is prohibited; form UserRegisterForm needs updating.
在 stackoverflow 上找到有类似的报错,排在前面的几个解决方法:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__' # Or a list of the fields that you want to include in your form
意思是 需要将 fields 的字段改为 __all__
,或者在你的 form 中想去 include 的字段,这里我就是想要 username 和 email 。
或者:使用 exclude = ()
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
exclude = ()
我尝试了两种,只有后面这种可以解决,第一种使用 __all__
依旧报错,什么原因呢?不明白,最后才发现我写的 field 是单数,应该是 fields ,好吧,知道了。
3. 拓展 User 后,不删除原有数据登录会失败
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
# 当 userprofile 这个 app 没有改动 model 时不用迁移数据。
# 用户拓展信息
class Profile(models.Model):
# 与 User 模型构成一对一的关系
# 每个Profile模型对应唯一的一个User模型,形成了对User的外接扩展
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
phone = models.CharField(max_length=20, blank=True)
avatar = models.ImageField(upload_to='avatar/%Y%m%d/', blank=True)
bio = models.TextField(max_length=500, blank=True)
def __str__(self):
return f'user {self.user.username}'
# 信号接收函数,每当新建 User 实例时自动调用
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
# 信号接收函数,每当更新 User 实例时自动调用
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
每个Profile
模型对应唯一的一个User
模型,形成了对User的外接扩展,因此你可以在Profile
添加任何想要的字段。这种方法的好处是不需要对User
进行任何改动,从而拥有完全自定义的数据表。
迁移好数据后,如果试图登录用户,会得到报错。这是因为之前创建的User
数据都没有对应的Profile
模型,违背了现有的模型。一种解决办法就是干脆删除旧的数据,因此就需要用到Django的shell
命令。
输入下面两行指令就可以轻松删除User数据库:
(env) D:\django_learning\blog_project>python manage.py shell
Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: zhuyuping>, <User: taijialan>, <User: zyp>]>
>>> User.objects.all().delete()
(17, {'admin.LogEntry': 9, 'auth.User_groups': 0, 'auth.User_user_permissions': 0, 'article.ArticlePost':5, 'userprofile.Profile': 0, 'auth.User': 3})
因为前面写的article
模型中,与User
的外键也采用了models.CASCADE
级联删除模式,因此随着User的删除,相关的文章也一并删除了。
输入exit()
退出shell
,输入指令python manage.py createsuperuser
,重新创建管理员账户。
4. Profile.objects.get(user_id=id).exists() 出错
报错提示:{AttributeError}‘Profile’ object has no attribute ‘exists’,‘Profile’ object 只有我写的一些特殊具体的属性,没有exists属性或方法。
通过 dir(Profile.objects.filter(user_id=id))
,可以证明通过 filter 可以产生 exists 属性。
5. 被包含的子路由模块需要添加app_name属性
# blog_project/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('article/', include('article.urls', namespace='article')),
path('userprofile/', include('userprofile.urls', namespace='userprofile')),
path('password-reset/', include('password_reset.urls')),
path('comment/', include('comment.urls', namespace='comment')), # 报错位置
]
File "D:\django_learning\blog_project\blog_project\urls.py", line 26, in <module>
path('comment/', include('comment.urls', namespace='comment')),
File "D:\env\lib\site-packages\django\urls\conf.py", line 39, in include
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_
name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the
list of patterns and app_name instead.
在新增 comment 评论的模型时,通过 python manage.py startapp comment
新建一个评论的app,然后在 setting 中的 INSTALLED_APPS 列表添加 ‘comment’,在主路由中配置子路由,接着编写 comment 的模型类,写完后需要迁移数据库,执行 python manage.py makemigrations
, 这时候出现上面这个报错。
报错信息是指,在 include() 中没有提供给一个支持的 app_name,需要在被包含的子模块(这里是 comment 目录下的 urls.py 模块)中设置 app_name 属性。
具体原因是在 comment 的 urls.py 文件中没有写该 app_name = ‘comment’, 以及配置 urlpatterns。
# comment/urls.py
app_name = 'comment'
urlpatterns = []
再次执行迁移:
(env) D:\django_learning\blog_project>python manage.py makemigrations
Migrations for 'comment':
comment\migrations\0001_initial.py
- Create model Comment
6. 使用F12检查没有展示的元素
模板中已经写好前端的展示,视图函数也给前端传参了,但是实际就是没有显示。
通过F12查看元素,可以发现该标签中没有内容,应该是没有从视图中获取到标签、或者获取到后经过前端操作后没有拿到该有的标签。
自然地,先检查视图函数有没有给前端模板传递对象,然后回到该页面的 html 代码中检查,发现是 html 中的变量 articles 写错了。
{% for article in articles %}
{% for tag in articles.tags.all %}
<a href="#" class="badge badge-secondary">{{ tag }}</a>
{% endfor %}
7. A server error occurred. Please contact the administrator.
修改 django 文件:D:\env\Lib\site-packages\django\views\debug.py,在打开文件时使用 utf-8,这样修改后,可以在页面看到具体的报错,而不只是一串“A server error occurred. Please contact the administrator.”。
def get_traceback_html(self):
"""Return HTML version of debug 500 HTTP error page."""
with Path(CURRENT_DIR, 'templates', 'technical_500.html').open(encoding='utf-8') as fh:
t = DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), use_l10n=False)
return t.render(c)
no such column 报错:删库解决。。。重新生成迁移文件、创建数据。
8. 部署
以前还买了阿里云服务器,后来就没有续费了。现在在本地的 Ubuntu 上部署测试。
-
修改 Django 的配置文件
# my_blog/settings.py # 关闭调试模式 DEBUG = False # 允许的服务器 ALLOWED_HOSTS = ['*'] # 静态文件收集目录 STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
-
虚拟环境一般是需要在服务器上重新生成的
安装包:
sudo apt-get update sudo apt-get upgrade sudo apt-get install python3 sudo apt-get install python3-pip sudo apt-get install git sudo pip3 install virtualenv
从远程库中拉取项目代码:
git clone https://gitee.com/zypdominate/django_learning.git
cd 进入项目中,生成虚拟环境,并激活:
virtualenv --python=python3.6 env source env/bin/activate
安装库、收集静态资源、数据迁移了:
pip3 install -r requirements.txt python manage.py collectstatic python3 manage.py migrate
代码部署基本就完成了,接下来配置
Nginx
安装 nginx:
sudo apt-get install nginx
启动 nginx,查看安装的 nginx 是否正常:
sudo service nginx start
打开浏览器,输入你的服务器公网 IP 地址(可在Ubuntu上试用)查看效果。
接着,重新写 Nginx 的配置文件。进入
/etc/nginx/sites-available
目录,这里是定义 Nginx 可用配置 的地方。输入指令sudo vi dusaiphoto.com
创建配置文件,以下是已经配置好的:zyp@zyp-virtual-machine:/etc/nginx/sites-available$ ls default my_blog sites zyp@zyp-virtual-machine:/etc/nginx/sites-available$ cat my_blog server { charset utf-8; listen 80; server_name 192.168.171.128; # 暂时是我本地的Ubuntu的ip地址 location /static { root /home/zyp/sites/django_learning/blog_project/collected_static; } location /media { root /home/zyp/sites/django_learning/blog_project/media; } location / { proxy_set_header Host $host; proxy_pass http://unix:/tmp/192.168.171.128.socket; } }
写的只是 Nginx 的可用配置,所以还需要把这个配置文件链接到在用配置上去:
sudo ln -s /etc/nginx/sites-available/my_blog /etc/nginx/sites-enabled
zyp@zyp-virtual-machine:/etc/nginx/sites-available$ ls default my_blog sites zyp@zyp-virtual-machine:/etc/nginx/sites-available$ sudo ln -s /etc/nginx/sites-available/my_blog /etc/nginx/sites-enabled ... zyp@zyp-virtual-machine:/etc/nginx/sites-enabled$ ls my_blog sites
至此 Nginx 就配置好了,接下来搞定
Gunicorn
:- 安装
Gunicorn
- 重启
Nginx
服务 - 启动
Gunicorn
先回到项目所在的目录,并且进入虚拟环境,然后输入:
(myenv) zyp@zyp-virtual-machine:~/sites/django_learning/blog_project$ pip3 install gunicorn (myenv) zyp@zyp-virtual-machine:~/sites/django_learning/blog_project$ sudo service nginx reload (myenv) zyp@zyp-virtual-machine:~/sites/django_learning/blog_project$ gunicorn --bind unix:/tmp/192.168.171.128.socket blog_project.wsgi:application
也可以用
sudo service nginx restart
,区别是 reload 只重载配置文件,restart 重启整个服务。最后打开浏览器,访问服务器查看效果。
- 安装
9. css、js等没有加载出来
本地调试好工程后,服务起来后在浏览器上测试也是正常的,但是一部署后就发现浏览器中没有加载css、js等,只有单纯的html格式,经过查看 nginx 的日志发现了问题:没有所需要的文件。
怎么会没有该文件呢?于是查看了 nginx 的配置文件:
server {
charset utf-8;
listen 80;
server_name 192.168.171.128; # 暂时是我本地的Ubuntu的ip地址
location /static {
root /home/zyp/sites/django_blog_tutorial/collected_static;
}
location /media {
root /home/zyp/sites/django_blog_tutorial/media;
}
location / {
proxy_set_header Host $host;
proxy_pass http://unix:/tmp/192.168.171.128.socket;
}
}
然后查看工程中 collected_static 目录下,发现没有 static 目录,所需要的 css、js文件都直接在 collected_static 目录下,也就是少了中间件一层 static。可以推理是在执行 python manage.py collectstatic
后出现的问题,排查发现在 settings.py 文件中的静态文件收集目录的路径有误:
# 静态文件收集目录
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
添加 static 后就可以展示 css、js等了:
# 静态文件收集目录
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static/static')
同理,media 目录中存放的资源在页面中加载不出来,也是路径的问题。其实这边可以修改工程中的 settings.py 文件,也可以更改 nginx 中的配置文件。
最后,终于改好了: