<p>在学习这个之前,首先要求是你们会Django框架的基础之上,如果不会可以<a href='https://blog.songshao.site/single/10007/'>点击这里</a>学习有关Django框架的一些使用方案,在下面我将会讲出有关api的简单编写和json数据处理过程。</p> <p>api结构主要包括请求链接,入参,Django的业务逻辑处理,返回参数。一般情况下尽量使用POST请求,数据比较安全。</p> <ol> <li><p>Django的业务逻辑</p> <ol> <li><p>urls的编写</p> <p>两种方法的原因是1.7以前不支持path来编写</p> <pre><code class='language-python' lang='python'>Django2.0.4可以使用以下方法 from django.urls import path urlpatterns = [ path('depot/', get_depot), path('depot_list/', get_depot_list) ] Django1.7.0可以使用以下方法 from django.conf.urls import url urlpatterns = [ url(r'depot/$', get_depot), url(r'depot_list/$', get_depot_list) ] </code></pre> </li> <li><p>models创建</p> <p>就举个简单的栗子吧,这样更加明确直白,这三个表个栗子,可以解决以后的多表联合查询问题。</p> <pre><code class='language-python' lang='python'># 停车场表 class TB_DEPOT(models.Model): DE_ID = models.CharField(max_length=18, verbose_name="停车场编码", primary_key=True) NAME = models.CharField(max_length=11, verbose_name="停车场名称") ADDRESS = models.CharField(max_length=64, verbose_name="停车场地址") LATITUDE = models.CharField(max_length=18, verbose_name="坐标(纬度)") LONGITUDE = models.CharField(max_length=18, verbose_name="坐标(经度)") COST_1 = models.CharField(max_length=6, verbose_name="停车费用_1") COST_2 = models.CharField(max_length=6, verbose_name="停车费用_2",null=True) MAN_COST = models.CharField(max_length=6, verbose_name="日最高消费",null=True) FREE_TIME = models.CharField(max_length=6, verbose_name="免费时长",null=True) MODE_PAY = models.CharField(max_length=11, verbose_name="支付方式") START_DATE = models.TimeField(verbose_name="营业开始时间") END_DATE = models.TimeField(verbose_name="营业结束时间") STATE = models.IntegerField(verbose_name="停车场状态") IMAGE_1 = models.ImageField(verbose_name="图片一", upload_to=image_upload_to) IMAGE_2 = models.ImageField(verbose_name="图片二", null=True, upload_to=image_upload_to) IMAGE_3 = models.ImageField(verbose_name="图片三", null=True, upload_to=image_upload_to) IMAGE_4 = models.ImageField(verbose_name="图片四", null=True, upload_to=image_upload_to) BUSI_ID = models.ForeignKey(TB_BUSINESSMAN, verbose_name="商户编码", on_delete=models.CASCADE) def __str__(self): return self.DE_ID class Meta: db_table = "TB_DEPOT" verbose_name = '停车场' verbose_name_plural = verbose_name # 预约表(TB_APPOINTMENT) class TB_APPOINTMENT(models.Model): APPO_ID = models.CharField(max_length=18, verbose_name="预约编码", primary_key=True) USER_ID = models.CharField(max_length=18, verbose_name="预约人编码") DATE = models.DateField(verbose_name='预约时间') PL_NUM = models.CharField(max_length=10, verbose_name='预约车牌', default='') APPO_TIME = models.CharField(max_length=4, verbose_name="预约时长") COST = models.CharField(max_length=4, verbose_name="预约费用") STATE = models.IntegerField(verbose_name="预约付款状态") APPO_STATE = models.IntegerField(verbose_name='预约过期状态', default='1') OUTPUT = models.IntegerField(verbose_name='是否入场', default='0') DEPOT = models.ForeignKey(TB_DEPOT, verbose_name="停车场编码", on_delete=models.CASCADE) def __str__(self): return self.APPO_ID class Meta: db_table = "TB_APPOINTMENT" verbose_name = '预约' verbose_name_plural = verbose_name # 用户表(TB_USER) class TB_USER(models.Model): OPEN_ID = models.CharField(max_length=64, verbose_name='微信唯一标识') USER_ID = models.CharField(max_length=32, verbose_name='用户编码') PHONE = models.CharField(max_length=11, verbose_name='用户手机号', null=True, default='') USER_NAME = models.CharField(max_length=32, verbose_name='用户微信名称') USER_STATE = models.IntegerField(verbose_name='用户状态') def __str__(self): return self.OPEN_ID class Meta: db_table = "TB_USER" verbose_name = '用户' verbose_name_plural = verbose_name </code></pre> </li> <li><p>api方法的编写</p> <p>先看一个简单的查询业务案例,停车场表信息查询</p> <pre><code class='language-python' lang='python'>from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt #请求参数设置 #http://localhost:8000/Api/depot/ # 入参 无 # 返回json数据 def get_depot(request): if request.method == 'GET': try: data = {} depot = TB_DEPOT.objects.values() data['depot'] = list(depot) print(data['depot']) return JsonResponse({'success': True, 'data': data['depot']}) except Exception as e: return JsonResponse({'success': False, 'data': str(e)}) </code></pre> <p>主要问题就是如何把把QuerySet,数据转化成json数据,也就是Python中的字典,根据<code>depot = TB_DEPOT.objects.values()</code>获取到数据对象,然后使用下面这种简单的方法来把数据转化成json数据,<code>data['depot'] = list(depot)</code>,这种方法给大家解释一下他就是把获取到的数据对象转化成list对象,然后反身存储到data['depot']中,完成一个简单的转化。</p> <p>下面这个栗子稍微有点复杂通过请求链接传参,进行获取数据,进行数据查询,拼接,返回json对象。</p> <pre><code class='language-python' lang='python'># 用户预约信息查询 根据用户唯一标识openid进行查询 # 请求示例 # 请求示例:http://localhost:8000/Api/get_appo_over/?openId=****** # 入参设置,需要进行openid标识传入 # 可选参数:STATE、PPO_STATE、OUTPUT # 返回用户预约的记录 def get_appo_over(request): data = {} if request.method == 'GET': openid = request.GET.get('openId') state = request.GET.get('state') output = request.GET.get('output') appo_state = request.GET.get('appo_state') try: userid = TB_USER.objects.get(OPEN_ID=openid).USER_ID print(userid) appo = {} if state: appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(STATE=state)) elif appo_state: appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(APPO_STATE=appo_state)) elif output: appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid) & Q(OUTPUT=output)) else: appo = TB_APPOINTMENT.objects.filter(Q(USER_ID=userid)) data['appo'] = list(appo.values()) i = 0 for a in appo: print(a.DEPOT.DE_ID) depot = TB_DEPOT.objects.filter(DE_ID=a.DEPOT.DE_ID).values() data['depot'] = list(depot) print(data['depot']) data['appo'][i].update(data['depot'][0]) i = i + 1 return JsonResponse({'success': True, 'data': data['appo']}) except Exception as e: return JsonResponse({'success': False, 'data': 0}) </code></pre> <p>这个接口,主要是进行预约和相对应的停车场进行查询简单解释一下一些语句的用途</p> <p><code>openid = request.GET.get('openId')</code></p> <p>使用该代码来获取请求链接中的参数;</p> <pre><code class='language-python' lang='python'> i = 0 for a in appo: print(a.DEPOT.DE_ID) depot = TB_DEPOT.objects.filter(DE_ID=a.DEPOT.DE_ID).values() data['depot'] = list(depot) print(data['depot']) data['appo'][i].update(data['depot'][0]) i = i + 1 </code></pre> <p>这块代码主要是对预约记录进行解析出来,根据对应的a.DEPOT.DE_ID标识去进行停车场查询,将得到的数据转化,然后拼接到appo数据中,因为data['depot']和data['appo']都属于是dict类型的对象,可以使用update直接把数据更新到另一个里面注意的是如果直接更新,相同索引的值都会被替换掉,所以使用之前先对数据进行处理。</p> </li> <li><p>小程序端的请求方法</p> <pre><code class='language-javascript' lang='javascript'>var that = this wx.request({ url: 'http://127.0.0.1:8000/Api/get_appo_over/?openId=' + app.gloabData.openid + '&state=0', method: 'GET', // url: 'https://api.songshao.site/Api/get_appo_over/?openId=' + app.gloabData.openid + '&state=0', method: 'GET', header: { 'content-type': 'application/json,charset=utf-8' }, success: function (res) { console.log(res.data.data) if (res.data.data.length == 0) { that.setData({ num: 0 }) } else { that.setData({ num: 1, appo: res.data.data, }) } }, fail: function (res) { wx.showToast({ title: '服务器开了小差,下拉刷新一下', icon: 'waring', duration: 3000 }) } }) </code></pre> <p> </p> <p>小程序使用wx.request来请求api,在url中编写链接地址和对应的参数,请求method一般尽量使用post,请求头设置 header: { 'content-type': 'application/json,charset=utf-8' },成功之后返回数据处理请求成功数据如下:</p> <pre><code class='language-json' lang='json'>{"success": true, "data": [{"APPO_ID": "684407", "USER_ID": "8208225", "DATE": "2018-12-25", "PL_NUM": "\u9655A88888", "APPO_TIME": "10", "COST": "0.5", "STATE": 1, "APPO_STATE": 1, "OUTPUT": 0, "DEPOT_id": "20181215002", "DE_ID": "20181215002", "NAME": "\u5c1a\u54c1\u7f8e\u5730\u57ce\u4e8c\u671f", "ADDRESS": "\u9655\u897f\u7701\u897f\u5b89\u5e02\u96c1\u5854\u533a\u9526\u4e1a\u8def92\u53f7", "LATITUDE": "34.34627", "LONGITUDE": "108.93984", "COST_1": "5", "COST_2": "6", "MAN_COST": "50", "FREE_TIME": "0.5", "MODE_PAY": "\u7535\u5b50\u652f\u4ed8", "START_DATE": "00:00:00", "END_DATE": "23:59:00", "IMAGE_1": "index/static/upload_image/47735b874b494483b1ab1149b1b6d84d/\u5c1a\u54c1.jpg", "IMAGE_2": "index/static/upload_image/d03235beb44548de9cab02041ba2d511/\u5c1a\u54c1.jpg", "IMAGE_3": "index/static/upload_image/14545c2c9f4a4e2ebf392a3fe04bc1af/\u5c1a\u54c1.jpg", "IMAGE_4": "index/static/upload_image/4bb82db280584fa6a6e4f91fde65f7e5/\u5c1a\u54c1.jpg", "BUSI_ID_id": "20181215001"}, {"APPO_ID": "9276129", "USER_ID": "8208225", "DATE": "2018-12-25", "PL_NUM": "\u9655E88888", "APPO_TIME": "10", "COST": "0.5", "STATE": 1, "APPO_STATE": 0, "OUTPUT": 0, "DEPOT_id": "20181215002", "DE_ID": "20181215002", "NAME": "\u5c1a\u54c1\u7f8e\u5730\u57ce\u4e8c\u671f", "ADDRESS": "\u9655\u897f\u7701\u897f\u5b89\u5e02\u96c1\u5854\u533a\u9526\u4e1a\u8def92\u53f7", "LATITUDE": "34.34627", "LONGITUDE": "108.93984", "COST_1": "5", "COST_2": "6", "MAN_COST": "50", "FREE_TIME": "0.5", "MODE_PAY": "\u7535\u5b50\u652f\u4ed8", "START_DATE": "00:00:00", "END_DATE": "23:59:00", "IMAGE_1": "index/static/upload_image/47735b874b494483b1ab1149b1b6d84d/\u5c1a\u54c1.jpg", "IMAGE_2": "index/static/upload_image/d03235beb44548de9cab02041ba2d511/\u5c1a\u54c1.jpg", "IMAGE_3": "index/static/upload_image/14545c2c9f4a4e2ebf392a3fe04bc1af/\u5c1a\u54c1.jpg", "IMAGE_4": "index/static/upload_image/4bb82db280584fa6a6e4f91fde65f7e5/\u5c1a\u54c1.jpg", "BUSI_ID_id": "20181215001"}]} </code></pre> <p>首先需要说明小程序请求之后会把json数据默认存放方到data里面,这块本省还有一个data,所以定位时就需要用res.data.data定位数据,像这个json数据有两条,在页面显示时可以用for循环输出数据</p> <pre><code class='language-html' lang='html'><view class='content_view' wx:for='{{appo}}' wx:key> <view class='header'> <text class='l_text'>{{item.DATE}}</text> <text class='r_text'>未进场</text> </view> <view class='header_content'> <view class='header_text'> <text>{{item.NAME}}停车场</text> </view> <view class='text_view'> <image class='image_style' src='../../resource/image/ding_wei_1.png'/> <text class='text_view_text'>{{item.ADDRESS}}</text> </view> <view class='text_view'> <image class='image_style' src='../../resource/image/car.png'/> <text class='text_view_text'>预约车牌为:{{item.PL_NUM}}</text> </view> <view class='text_view'> <image class='image_style' src='../../resource/image/time.png'/> <text class='text_view_text'>剩余时长:{{item.APPO_TIME}}</text> </view> <button class='btn'>续费</button> </view> </view> </code></pre> <p>在循环中可以通过定义的数据对象appo,去循环,因为循环使用的是它的array(),因为json对象有两条所以循环两次,输出,每次遍历数组对象是可以使用item.属性名,来获取相应的数据,显示结果如下图所示</p> <p><img src='/static/upload/xiaochengx_list1.png' alt='xiaochengx_list1' referrerPolicy='no-referrer' /></p> <p>如果出现这种结果就说明你的小程序成功了!</p> </li> </ol> </li> </ol>
Django (1054, "Unknown column 'django_co
<p>问题说明:本人是把Django2.0.4的应用部署到Django1.7.0的服务器版遇到的问题</p> <p>解决方案一:很简单你可以把你服务器版本升级到1.8 以上就可以了,但是如果你用的是window系统那就不行了,Windows系统上面现在可以部署的环境是1.7以下,很遗憾,该方法行不通。</p> <p> </p> <p>解决方案二:下面这种方案有点烦,但是可以在所有版本中通用。</p> <p> 在数据库中找到该django_content_type表,错误提示的意思是说明没有找到name field list ,哪咱就给这个表创建一个name出来,值就是对应的models里面设置的verbose_name的值,该方案很实用。</p>
Django框架 样式丢失问题解决方法
<p>之所以说这个问题的原因是因为我部署服务器用的是nigex+faceCGI在window 2008 R2服务器上进行部署的服务器,在服务器部署完成之后就出现了很多无法预测到的问题,这也是我在学习过程中遇到的一个让人可以头皮发麻的问题,现在就总结一下自己的一点点经验。</p> <p>下面是我个人的解决方案仅供参考:</p> <ol start='' > <li><p>首先在settings.py文件配置一个静态文件资源地址</p> <pre><code>STATIC_ROOT = 'C:/Programs/Project/songs/static/' </code></pre> </li> <li><p>然后使用下面命令在复制所有用到的静态文件到,该目录下</p> <pre><code>python manage.py collectstatic </code></pre> </li> <li><p>最后进行配置静态文件路由</p> <pre><code>import songs.settings from django.conf.urls import url url(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': songs.settings.STATIC_ROOT }) </code></pre> </li> <li><p>进行测试可以查看源代码,点击样式资源路径如果可以读取到文件说明配置成功,否则失败!</p> <p>看看效果:</p> <p><img src='/static/upload/css_one.png' alt='css_one' referrerPolicy='no-referrer' /></p> </li> </ol> <p><img src='/static/upload/css_one_1.png' alt='css_one_1' referrerPolicy='no-referrer' /></p> <p>如果是这样就要恭喜您配置成功!</p>
windows 2008 R2 nginx+FastCGI+Django 部署
<p>温馨建议软件使用版本python3.4、Django1.7、nginx1.2、flup1.0.3, 使用这三个版本是有原因的否则我也不会这样,在windows 上面我能考虑到用这种情况是因为我刚开始使用apache+mod_wsgi进行部署的但是不知道什么原因愣是有个问题没办法解决,我本以为是版本问题后来更换版本也不行,在httpd.conf文件进行module加载的时候路径正确也读不出来,直接导致服务无法启动,有人说去自动生成一个模板路径但是还是不行;再后来我去使用nginx+uwsgi进行部署使用,这时候又出现一个问题window系统上面没办法安装uwsgi资源库,没办法只能放弃上面两种办法了。</p> <ol start='' > <li><h5>ngin安装及配置</h5> </li> <li><p>nginx下载地址:<a href='http://nginx.org/en/download.html' target='_blank' class='url'>http://nginx.org/en/download.html</a> </p> </li> <li><p>进行nginx解压,我这块解压路径C:\Program\nginx-1.12.2;</p> </li> <li><p>然后去下载一个安装nginx的神器,windows service wrapper,这块藐视现在只有1.9版本的winsw-1.9-bin.exe。把它放在这个解压目录下创建一个winsw文件;</p> </li> <li><p>然后在该目录下创建与神器名字相同的xml文件winsw-1.9-bin.xml</p> <pre><code><?xml version="1.0" encoding="UTF-8" ?> <service> <id>nginx</id> <name>nginx</name> <description>nginx</description> <executable>C:\Program\nginx-1.12.2\nginx.exe</executable> <logpath>C:\Program\nginx-1.12.2\</logpath> <logmode>roll</logmode> <depend></depend> <startargument>-p C:\Program\nginx-1.12.2</startargument> <stopargument>-p C:\Program\nginx-1.12.2 -s stop</stopargument> </service> </code></pre> </li> <li><p>进入该C:\Program\nginx-1.12.2\winsw\文件下安装服务:</p> <pre><code>winsw-1.9-bin.exe install </code></pre> </li> <li><p>配置conf/nginx.conf文件主要配置服务:</p> <pre><code>server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root index; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } #重点在这,这个路径是你创建的Django项目的主文件路径 location ~* ^.+\.(html|jpg|jpeg|gif|png|ico|css|js)$ { root D:/myjango; expires 30d; break; } # 加载静态资源路径 location ~ ^/static/ { root D:/myjango; expires 30d; break; } # fastcgi 配置相关的ip和端口方便去调用 location ~ ^/ { fastcgi_pass 127.0.0.1:8051; fastcgi_param PATH_INFO $fastcgi_script_name; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_pass_header Authorization; fastcgi_intercept_errors off; } } </code></pre> </li> <li><p>negix常用命令</p> <pre><code>启动命令:start negix 停止命令: negix -s quit </code></pre> <p> </p> </li> </ol> <h5>2.FastCGI安装</h5> <p>2.1 FastCGI安装用的是flup,可直接用pip3 安装版本最新版是1.0.3。1.0.2主要是用在py2上的如果用在py3中会出现安装中的错误。</p> <pre><code>pip3 install flup </code></pre> <p>2.1 在项目目录下运行该程序</p> <pre><code>manage.py runfcgi method=threaded host=127.0.0.1 port=8051 </code></pre> <p>在项目运行中尽量不要使用Django,太高版本的操作否则会出现你意向不到的问题,如果正常执行完这个命令项目是没有任何反应和提示信息的,否则就出错误了。</p> <h4>问题归纳:</h4> <ol start='' > <li><p>路由配置</p> <p>在Django路由配置方面尽量使用django.conf.urls 下面的url进行配置</p> <p>基本规则示例如下:</p> </li> </ol> <pre><code>from django.contrib import admin from django.conf.urls import url,include from index.views import * urlpatterns = [ url(r'^admin/$', admin.site.urls), url(r'', include('index.urls')), # 引入另一个应用urls ] </code></pre> <ol start='2' > <li><p>settings.py配置</p> <p>在setting配置中主要就是要配置DEBUG改为False,还有一个东西很重要,看下面:</p> <p> 不知道在那个版本的Django框架中MIDDLEWARE_CLASSES被改成了MIDDLEWARE导致在runfcgi时会报没有在MIDDLEWARE_CLASSES中配置'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',这三个参数,导致错误,不能继续编译。</p> <pre><code>MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] MIDDLEWARE_CLASSES = [ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ] </code></pre> </li> <li><p>项目分页情况</p> <p>在Django2.0.3版本使用下面方法就可以完成分页:</p> <pre><code>from django.core.paginator import Paginator paginator = Paginator(article, 4) page = request.GET.get('page') art = paginator.get_page(page) </code></pre> <p>在Django1.7版本以前可以使用下面方法来完成:</p> <pre><code>from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger page = request.GET.get('page') #art = paginator.page(page) try: art = paginator.page(page) except PageNotAnInteger: art = paginator.page(1) except EmptyPage: art = paginator.page(paginator.num_pages) </code></pre> <p>出现这这种原因是因为Django版本更新去掉了一些复杂的方法简化了,所以之前的版本就不能用了。</p> </li> <li><p>还有一些没有碰见的问题希望有心人能够留下你们的一些想法或者思路或者问题都可以。</p> </li> </ol>