接上周的django继续学习,这周的目标是能够利用python搭建图片处理的后台,继续根据官方文档完成mysite搭建并自己搭建证件照换底色后台
在自己定义的app中的views.py里定义不同的响应函数,并在urls指定调用view.function
的方式,例如:
urlpatterns = [
# ex: /polls/
path('', views.index, name='index'),
# ex: /polls/5/
path('/' , views.detail, name='detail'),
# ex: /polls/5/results/
path('/results/' , views.results, name='results'),
# ex: /polls/5/vote/
path('/vote/' , views.vote, name='vote'),
]
不同级别的访问会对应不同的path,从而调用不同的函数的HTTP响应,从而显示到页面上,<>
中的匹配为正则匹配
结果显示为:
一个真正可以利用的视图必须能够从数据库中读取记录,可以使用模板等功能,官方文档给了以下实例,polls/views.py
的代码如下:
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
从models下导入Question,然后再polls下建立templates目录,然后再新建一个polls目录,目录下放index.html,此为模板文件,官方文档指出,由于APP_DIRS设置为TRUE,所以可以直接利用模板加载器,使用路径为polls/index.html
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
接下来使用模板
from django.http import HttpResponse
from django.template import loader
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))
loader获取到index.html模板,并导入问题列表,生成超链接,每一个连接都连接到对应的具体的问题
然而官方提到一个更快捷的函数render(),该函数通过from django.shortcuts import render
导入
from django.shortcuts import render
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
直接将模板作为参数放在render里执行
from django.http import Http404
from django.shortcuts import render
from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
直接在http包中导入404,然后通过异常检测的方式,如果没有获取到对应的问题号,就返回404页面
get_object_or_404()
可以直接判断而不用使用异常判断,返回根据情况而定
去除模板中的硬编码URL
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}a>li>
改写为
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}a>li>
这样在改变polls时,只用改变一处即可
为URL名称添加命名空间
也就是说在应用很多的情况下,同样是detail视图,URL应该对应哪一个应用
官方文档指出:在根 URLconf 中添加命名空间,例如:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('/' , views.detail, name='detail'),
path('/results/' , views.results, name='results'),
path('/vote/' , views.vote, name='vote'),
]
加上app_name=polls
设置命名空间
这样一来,index.html中的url'detail'
应改为url'polls:detail'
使用官方给我们的表单模板,更改vote()的具体实现
polls/templates/polls/detail.html
<h1>{{ question.question_text }}h1>
{% if error_message %}<p><strong>{{ error_message }}strong>p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}label><br>
{% endfor %}
<input type="submit" value="Vote">
form>
polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
# ...
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
//选中的项目的投票数加1
selected_choice.votes += 1
//保存
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
//转到结果界面
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
这样以后,在跳转到detail界面时,可以将所有choice以单选框的形式打印在界面上,每个单选框的 name
是 "choice"
。这意味着,当有人选择一个单选按钮并提交表单提交时,它将发送一个 POST 数据 choice=#
,其中# 为选择的 Choice 的 ID。
POST完成后返回页面重定向,定向到result界面,reverse()调用返回'/polls/3/results/'
接下来编写results.py视图
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
然后在static文件夹下写入result.html
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
还是以这种模板的方法写入
点击投票,会跳转到results页面
由以上例子可以看出代码存在冗余,django官方文档支出了通用视图
在应用下的urls.py中更改path()中的参数,以polls为例,在polls/urls.py
下
path('', views.IndexView.as_view(), name='index'),
path('/' , views.DetailView.as_view(), name='detail'),
path('/results/' , views.ResultsView.as_view(), name='results'),
路径字符串中匹配模式的名称已经由
改为
改良视图,打开polls/views.py
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
原来的视图可以对应删除
在学习django过程中也找到了一些网上有人做出来的网站demo,找到了一个图书管理网站,github地址:https://github.com/hyyc554/mydjango
项目的md文件列出了一个django框架示意图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
项目目录
然后就是连接mysql
先下载mysql,我用的是Apache的XAMPP管理工具,默认端口号为3306,终端输入mysql -uroot -p
回车,然后输入密码进入mysql界面,进入mysql数据库管理工具,我用的是NavicatMysql,连接数据库,创建数据库名等操作,数据库名和连接密码需要依据settings.py文件的配置
我没有设置数据库连接密码,如果有设置这里可以添加,然后创建orm3数据库,在项目的终端运行python manage.py migrate
将会执行数据库迁移,这个时候你就会看到数据库中设置了表,但是全为空值,可以在里面插入数值
然后在网页中打开localhost:8000/app01/books
这里我手动添加了一个书籍,一开始应该为空,可以添加书籍,但是注意数据库中必须有作者和出版社的日期,才能成功添加书籍
至此,这个django实例就运行成功,内部的项目结构逻辑其实类似官方文档所讲述的那样
和伙伴一起搜集了几天资料,终于在14号开始后台django搭建,他给了我几篇参考文章,我觉得十分有帮助
https://blog.csdn.net/qq_41775298/article/details/105301801?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-1.nonecase
https://blog.csdn.net/wf021017/article/details/105417547/?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-3&spm=1001.2101.3001.4242
https://blog.csdn.net/qq_29391809/article/details/104002696
关于小程序的相关知识可以参考我的第一周学习记录博客https://blog.csdn.net/weixin_43951163/article/details/107928486,然后也可以参考我伙伴的博客https://blog.csdn.net/qq_44933075/article/details/107735724
根据三篇文章的前两篇先进行后台获取用户上传图片
首先搭建django框架,pycharm新建一个项目,在项目终端输入python manage.py startapp 'app名称'
然后在新建app下新建urls.py
更改settings.py的ALLOWED_HOSTS = ['*']
,然后添加app到序列中
我的项目目录如下
我创建的app名为pc_change,然后我把前端的css文件放在静态文件夹下,前端index代码放在templates模板下
添加cqc_01下的urls.py的代码
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('app/', include('pc_change.urls'))
]
然后更改pc_change下的urls.py和views.py
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('get_image/', views.get_image),
]
views.py
from django.shortcuts import render
import pc_change.method
import os
from django.http import HttpResponse,HttpResponseRedirect
# Create your views here.
def get_image(request):
if request.method == 'POST':
image = request.FILES['image']
print(image)
open_id = request.POST.get('openid')
//这里是项目的绝对路径
basedir = '/Users/shall/PycharmProjects/cqc_01'
//我这里把图片放在静态文件资源下的images文件夹下,之后进行数据库开发会将其放在数据库中
path = basedir + '/static/images/'
if not os.path.exists(path + open_id + '.jpg'):
with open(path + open_id + '.jpg', 'wb') as f:
f.write(image.read())
f.close()
return HttpResponse('上传成功')
else:
return HttpResponse('上传失败')
然后对于小程序的wx.upload编写
wx.uploadFile({ // 调用接口上传文件
//url测试为本主机测试,可以根据自己的app更改
url: 'http://localhost:8000/app/get_image/',
// url: 'http://www.baidu.com',
filePath: filePath,
name: 'image',
method: 'POST',
formData: {
openid: that.data.openID
},
success: res => { // 调用成功时的回调函数
console.log('[上传文件] 成功:', res)
wx.showToast({
title: '上传成功',
icon:'success'
})
},
fail: e => { // 调用失败时的回调函数
console.error('[上传文件] 失败:', e);
wx.showToast({ // 显示消息提示框
icon: 'none',
title: '上传失败',
})
},
complete: () => { // 调用完成时的回调函数
wx.hideLoading() // 隐藏加载提示框
}
})
},
fail: e => { // 调用失败时的回调函数
console.error(e)
}
})
}},
这个时候要注意将微信小程序界面中的详情中的如下打钩
然后上传图片,这个时候还会报错,console会显示app not found
找了一下解决方案,需要将settings.py中的一行注释掉
csrf这一行注释,然后就可以成功上传图片了,图片名为filepath+.jpg,存在images文件目录下
至此,本地后台的文件接收就完成了
同第一章的记录,打开mysql服务,然后在database中添加信息,然后不要忘记在_init_.py
中加入
import pymysql
pymysql.install_as_MySQLdb()
然后就可以正常连接了
首先创建model,model的创建要根据你拟定的表的格式,我创建的如下:
from django.db import models
# Create your models here.
class Before_Pic(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to='logo')
def __str__(self):
return self.name
在settings的数据库设置下加几条语句
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
然后要执行迁移:
python manage.py makemigrations
python manage.py migrate
随后要注意一点要在mysql中运行
SET @@global.sql_mode='';
这样避免了后面对于数据类型的报错
于是再次来到小程序点击上传,可以发现media目录下出现了logo文件下,文件夹下是我们的图片
然而这里图片显得很长,但是我先没有解决
mysql数据库中新增了一个数据
这样,用户上传的图片就成功存储在mysql中,但这与我想的不太一样,存入的图片是项目下的相对路径,也就是说图片仍然存储在项目文件中,数据库只是存储一个处理和调用的路径
这两天有事离开家,过几天继续更新