文章目录
最近又练习了一个基于 django 的小项目,在此过程中也遇到一些小问题,最后通过查找资料和debug等办法解决了,同时也将一些感觉比较好的bug记录了一下。
积跬步至千里,积小流成江海。加油!
1. 虚拟环境
最好在命令行中创建虚拟环境,如果用 pycharm 可能不不小心将本地的 Python 环境作为基础添加进去。
D:\>python
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.
>>> quit()
D:\>python -m venv env_testing
D:\>
D:\>cd env_testing/Scripts
D:\env_testing\Scripts>activate.bat
(env_testing) D:\env_testing\Scripts>
使用纯净的 Python 环境作为基础:
2. django 项目之始迁移文件
发现在通过 python manage.py runserver
启动服务后,可以访问:
但是无法访问 admin 的页面,报错如下:
......
File "D:\env_testing\lib\site-packages\django\db\backends\sqlite3\base.py", line 383, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: django_session
[17/Jun/2020 01:08:13] "GET /admin/ HTTP/1.1" 500 198090
需要迁移数据库:
(env_testing) D:\django_learning\api_testing>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
接着就可以访问 admin 了:
3. mysqlclient error
manage.py@api_testing > startapp login
......
......
File "D:\env_testing\lib\site-packages\django\db\backends\mysql\base.py", line 36, in <module>
raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
比较好的解决办法(亲测可用):找到引入 pymsql 的文件,然后添加版本信息,只需要一行代码。
import pymysql
pymysql.version_info = (1, 3, 13, "final", 0) # 解决mysql版本问题报错而添加的代码
pymysql.install_as_MySQLdb()
原因:
- Why do I know you are using pymysql? Because 0.9.3 is just the latest version of pymysql.
- Why use pymysql instead of mysqlclient for the project? Because it is easier to install. pymysql does not depend on system libraries, while mysqlclient relies on a series of system libraries such as libmysqlclient-dev.
- Why is mysqlclient difficult to install and Django still uses it by default? Because mysqlclient is faster and performs better. So if your project has high performance requirements, I suggest you remove the compatible code above and install mysqlclient in your project. If you need help during the installation of mysqlclient, please refer to this link: How to install Python MySQLdb module using pip?, and ensure
libssl-dev
has been installed beforepip install mysqlclient
.
其他方法:参考 stack overflow 上的其他建议。
ps:我特意先使用 google 搜索该问题,第一条搜索结果就可以解决该问题,而且还很简单;然后我去百度同样搜索,发现很多方法比较复杂,也没有软用,治标不治本,还浪费时间。
4. 运行时在 mysql 的 operations.py 中报错
(env_testing) D:\django_learning\api_testing>python manage.py runserver
......
File "D:\env_testing\lib\site-packages\django\db\backends\mysql\features.py", line 82, in is_sql_auto_is_null_enabled
cursor.execute('SELECT @@SQL_AUTO_IS_NULL')
File "D:\env_testing\lib\site-packages\django\db\backends\utils.py", line 103, in execute
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
File "D:\env_testing\lib\site-packages\django\db\backends\mysql\operations.py", line 146, in last_executed_query
query = query.decode(errors='replace')
AttributeError: 'str' object has no attribute 'decode'
处理办法:Go to django folder, then go to this path: django\db\backends\mysql
then go to operations.py
and find query = query.decode(errors='replace')
. Remove the line and put query = errors='replace'
def last_executed_query(self, cursor, sql, params):
# With MySQLdb, cursor objects have an (undocumented) "_executed"
# attribute where the exact query sent to the database is saved.
# See MySQLdb/cursors.py in the source distribution.
query = getattr(cursor, '_executed', None)
if query is not None:
# query = query.decode(errors='replace') # zhuyuping modify
query = errors = 'replace' # zhuyuping add
return query
5. 映射html出问题,函数不存在
NoReverseMatch at /register/
Reverse for 'login' not found. 'login' is not a valid view function or pattern name.
templates\login\register.html
:
<div class="margin-top20 text-center">
已经有账号了? <a href={% url 'login' %}>登录</a>
</div>
login\urls.py
:
app_name = 'login'
urlpatterns = [
path('', views.LoginView.as_view(), name='login'),
path('forgot/', views.ForgotView.as_view(), name='forgot'),
path('register/', views.RegisterView.as_view(), name='register'),
path('reset/', views.ResetView.as_view(), name='reset'),
]
需要指定app,所以修改为:
<div class="margin-top20 text-center">
已经有账号了? <a href={% url 'login:login' %}>登录</a>
</div>
同理,还有类似的写法也都是报这个错误。
6. register页面注册成功后跳转到login页面,但是url还是register
class RegisterView(View):
def get(self, request):
return render(request, 'login/register.html')
def post(self, request):
user_register_form = RegisterForm(data=request.POST)
if user_register_form.is_valid():
username = user_register_form.cleaned_data.get('username')
password = user_register_form.cleaned_data.get('password')
email = user_register_form.cleaned_data.get('email')
if not request.POST.get('aggree'):
return translate2json(errno=ResCode.AGGREE, errmsg=error_map[ResCode.AGGREE])
new_user = User.objects.create(username=username, password=password, email=email)
new_user.save()
return render(request, 'login/index.html')
else:
return HttpResponse("注册输入有误,请重新输入~")
在注册页面,注册一个用户:
提交注册数据后,跳转到登录页面:
如果直接填写信息登录,会出现错误,原因是当前网页的 url 并不是真正的登录(login)页面,所以提交的数据不能通过本应该是 login 的路由来发出 get 请求。仔细看页面的路由,依然是 register。
此时填写正确的注册过的用户数据,会返回注册过程的一些数据。(由于刚刚在注册页面注册了信息,数据被写入数据库,然后再在当前的假登录【实际还是注册的页面】进行登录,就相当于用原来的数据重新注册一次,当然这样是不允许的,在后端代码中就防止该行为出现而抛出异常。)
解决办法:使用 redirect 来重定向到真正的登录页面。
# return render(request, 'login/index.html')
return redirect('login:login')
从该定位该 bug 以及解决可知,以后凡是涉及页面跳转的,不仅要考虑前端页面,还有考虑跳转后的路由 url 是否与页面匹配,防止出现类似的问题。
同样的,在登录页面进行登录后进入首页,但是路由 url 并没有改变,刷新 url 后又回到了登录界面,显然是不合理的。
涉及的相关代码:
class LoginView(View):
def get(self, request):
return render(request, 'login/index.html')
def post(self, request):
try:
post_data = request.POST
if not post_data:
return translate2json(errno=ResCode.PARAMERR, errmsg="参数为空,请输入")
user_key = ["email", "password", "remember"]
data_dict = {}
for key in user_key:
data_dict[key] = post_data.get(key)
except Exception as e:
logging.info("错误信息:\n{}".format(e))
return translate2json(errno=ResCode.UNKOWNERR, errmsg=error_map[ResCode.UNKOWNERR])
login_form = LoginForm(data=data_dict, request=request)
if login_form.is_valid():
return render(request, 'home/index.html') # 问题原因
将 render 改为重定向:
# login\views.py
if login_form.is_valid():
# return render(request, 'home/index.html')
return redirect(reverse('index'))
# apiwork\urls.py
urlpatterns = [
path('index/', views.ApiView.as_view(), name='index')
]
# apiwork\views.py
class ApiView(View):
def get(self, request):
return render(request, 'home/index.html')
7. as_view()
路由中调用视图函数 as_view 函数后面需要加括号。
urlpatterns = [
path('index/', views.ApiView.as_view, name='index')
]
view.py是这样的:
class ApiView(View):
def get(self, request):
return render(request, 'home/index.html')
当前端发起 request 请求时,会报这样的错误:
TypeError at /apiwork/index/
as_view() takes 1 positional argument but 2 were given
Request Method: | GET |
---|---|
Request URL: | http://127.0.0.1:8000/apiwork/index/ |
Django Version: | 2.2 |
Exception Type: | TypeError |
Exception Value: | as_view() takes 1 positional argument but 2 were given |
urlpatterns = [
path('index/', views.ApiView.as_view(), name='index')
]
8. 前端返回数据有问题
9. 小结
通过这个小小的项目的学习练习,也发现自己在前端知识方面存在很多不懂的地方,需要好好弥补一下。不过由于现在练习的两个项目都是前后端不分离,这已经是落后的潮流了,以后的趋势是前后端分离,所以准备学一下目前大火的 Vue,正好也有一个前后端分离的项目可以用来练习。
很多模型以及设计方面的东西还是不太理解的,只是照葫芦画瓢,不过相比以前刚刚接触 django 来说,已经是进步很多了。有些 bug 的处理没有很好地办法,有的可以通过删库后重新迁移文件来解决,但是实际场景中肯定是不可以这样做的,也就是说很多 bug 的解决没有找到本质的原因、没有用最佳的方法解决,需要慢慢练习、向他人学习。
从一个 django 项目的练习中,可以发现哪些东西都要恶补,记录一下,加入到后续的学习计划中。
- HTTP
- 数据库
- django 的官方文档
- 前端,Vue