基于 django 博客项目中遇到的 bugs 及处理方法

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检查没有展示的元素

模板中已经写好前端的展示,视图函数也给前端传参了,但是实际就是没有显示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTMGd3zV-1592238552874)(others/somebug_6.png)]
通过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 上部署测试。

  1. 修改 Django 的配置文件

    # my_blog/settings.py
    
    # 关闭调试模式
    DEBUG = False
    
    # 允许的服务器
    ALLOWED_HOSTS = ['*']
    
    # 静态文件收集目录
    STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
    
  2. 虚拟环境一般是需要在服务器上重新生成的

    安装包:

    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 的日志发现了问题:没有所需要的文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMGJjnzm-1592238552897)(others/somebug_nginx_error.png)]
怎么会没有该文件呢?于是查看了 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 中的配置文件。

最后,终于改好了:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwmyCMDO-1592238552910)(others/somebug_blog_show.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值