django+mysql的CURD入门体验

在django官网的入门教程中,采用的是循序渐进的方式,基于一个问答投票的案例进行的讲解。另外也使用了Admin自动生成页面,这确实挺强大的。但看完后感觉有点乱乱的,有太多分支介绍,感觉不是最佳实践,只是为了介绍django的各种功能。

这里我根据平时项目中正常的流程顺序,重新梳理一下思路流程,形成一条主线以便记忆。

准备工作

  1. 安装django(install)
python -m pip install Django
  1. 创建项目(startproject)
django-admin startproject mysite
  1. 启动项目(runserver)
cd mysite
python manage.py runserver

看到如下输出,打开链接显示欢迎页

...
December 30, 2019 - 02:11:37
Django version 3.0.1, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

首次启动后,在项目根目录下会产生db.sqlite3文件
4. 创建应用(startapp)

python manage.py startapp polls
  1. 引入应用

mysite/settings.py添加polls应用配置

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
]

数据库相关

在官方示例中,默认使用的sqlite3,库表都是自动创建的,很强大但隐藏了很多细节。

这里我改成常用的Mysql

  1. 首先手动创建数据库
create schema my_site character set utf8;

修改settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'my_site',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '192.168.223.43',
        'PORT': '3306'
    }
}

重启项目如果没报错,说明数据库链接成功

  1. 生成默认表

根据INSTALLED_APPS中的依赖,自动生成相关的表到数据库中

python3 manage.py migrate

执行完后可以到数据库中查看多了auth、django打头的表。

这也是django的一大特性,即在提供功能插件的时候是全套的,包括数据库的自动生成,不用自己额外的去获取SQL,并且数据库的生成方式很优雅。

mysql> show tables;
+----------------------------+
| Tables_in_my_site          |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+
  1. 创建业务表

参照官方的投票示例建表,这里并没有先建Model然后用migrate生成表,而是使用我们平时开发的流程先手动建表,然后再到代码中建Model

-- 问题表
create table polls_question (
    id int auto_increment primary key ,
    question_text varchar(200) not null,
    pub_date timestamp NOT NULL default current_timestamp
);

-- 投标表
create table polls_choice (
    id int auto_increment primary key,
    question_id int not null,
    choice_text varchar(200) not null,
    votes int not null,
    foreign key (question_id) references polls_question(id)
);
  1. 定义模型(Model)

polls/models.py

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200, blank=False, null=False)
    pub_date = models.DateTimeField()


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

继承models.Model,定义了两个Model,里面的字段同数据库中的字段,另外指定了字段类型及相应的属性,也就是同数据库中的定义保持一致。

为什么不先定义Model再自动生成数据表呢,仅仅是为了理解来龙去脉,理解后谁先谁后可以随意。

按照装官方文档,下一步是createsuperuser,通过django强大的admin功能,自动生成页面来对刚才的两个Model进行CURD操作。有需要的可以参照文档体验一下。

  1. 定义视图-新增(View)

接口的定义有两种方式

  • 函数定义
  • 通用类定义

视图使用RESTful风格,但并不准备使用其他插件框架

通过继承View通用类来定义view,因为它可以通过定义get、post、put、delete的方法来匹配Http Method,返回类型都用JsonResponse,为了方便写了个BaseResult

common.py

class BaseResult:
    success = False
    error = None

    def __init__(self, success, error):
        self.success = success
        self.error = error

    def __init__(self, error):
        self.error = error

    def __init__(self):
        pass

    def toJSON(self):
        return {'success': self.success, 'error': self.error}

先看新增,post作为数据新增使用,那么就要涉及表单数据的接收和校验

views.py

from django.views import View
from django.core.paginator import Paginator
from .models import Question
from django.core.exceptions import ObjectDoesNotExist
from django.http import QueryDict, JsonResponse
from .common import BaseResult
from .forms import QuestionForm

class QuestionView(View):
    def post(self, request):
        result = BaseResult()
        form = QuestionForm(request.POST)

        if form.is_valid():
            form.save()
            result.success = True
        else:
            result.error = form.errors
        return JsonResponse(result.toJSON())

django提供来ModelForm来简化表单的处理

forms.py

from django import forms
from django.forms import ModelForm
from .models import Question


class QuestionForm(ModelForm):
    question_text = forms.CharField(error_messages={'required': '问题不能为空', 'max_length': '长度不能超过10'})

    class Meta:
        model = Question
        fields = "__all__"
  • model指定基于哪个Model,因为常规情况下表单的数据是对应Model的,所以这里不需要重复定义字段,直接借用
  • fields用于配置需要用到的字段有哪些,如果字段比较多可以一个__all__搞定,当然也可以一个个的写,或者反着来过滤某些字段都可以,具体看官方文档有介绍
  • form的第二个作用是要做参数校验,默认使用Model中的字段属性要求要做校验,例如长度和非空,但提示语是默认的,如果要自定义校验的提示语,就是上面error_messages的用法

再回过头看post方法,直接将request.POST丢给QuestionForm就可以拿到form提交的数据了。

紧接着做校验,成功就save,出错就返回errors。这里的一个强大之处是,form直接可以保存Model

接口定义好了,要去配置一下url

mysite/urls.py

from polls.views import QuestionView
urlpatterns = [
    #...
    path('polls/question/', QuestionView.as_view()),
]

为了方便调试去除settings.py中MIDDLEWARE的 django.middleware.csrf.CsrfViewMiddleware,否则会提示CSRF cookie not set

测试一下post接口

$ curl http://127.0.0.1:8000/polls/question/ -X POST -d 'question_text=喜欢的语言&pub_date=2019-12-30 17:00:00'

{"success": true, "error": null} 
  1. get分页查询
class QuestionView(View):
    def get(self, request):
        kwargs = {}
        if request.GET.get('question_text') is not None:
            kwargs['question_text__startswith'] = request.GET.get('question_text')
        if request.GET.get('pub_year') is not None:
            kwargs['pub_date__year'] = request.GET.get('pub_year')

        question_page = Paginator(Question.objects.filter(**kwargs),
                                  request.GET.get('size')).page(request.GET.get('page'))

        result_list = map(lambda q: {
            'question': q.question_text,
            'pub_date': q.pub_date
        }, question_page)

        return JsonResponse({
            "count": question_page.paginator.count,
            "data": list(result_list)
        }, safe=False, json_dumps_params={'ensure_ascii':False})
  • 由于查询条件是可选的,所以判断是否None,然后放入字典中,字典的key为Model query的表达式,字段与匹配方式之间用两个下划线连接。
  • 使用Paginator进行分页查询
  • 使用lambda对分页结果进行为JSON格式
$ curl -s "http://127.0.0.1:8000/polls/question/?page=1&size=5"   

{"count": 1, "data": [{"question": "喜欢的语言", "pub_date": "2019-12-30T09:00:00Z"}]}  
  1. put更新
class QuestionView(View):
    def put(self, request):
        result = BaseResult()

        put = QueryDict(request.body)
        try:
            q = Question.objects.get(pk=put.get('id'))
        except ObjectDoesNotExist:
            result.error = "ID不存在"
            return JsonResponse(result.toJSON())

        form = QuestionForm(put, instance=q)
        if form.is_valid():
            form.save()
            result.success = True
        else:
            result.error = form.errors

        return JsonResponse(result.toJSON())
  • 由于django的request对象中没有PUT属性,所以不能像GET、POST直接去除数据,得通过body转字典
  • 使用主键获取原数据,然后通过QuestionForm合并新旧数据
$ curl http://127.0.0.1:8000/polls/question/ -X PUT -d 'question_text=喜欢的语言&pub_date=2019-12-30 17:50:00&id=1'

{"success": true, "error": null}
  1. 删除数据
class QuestionView(View):
    def delete(self, request):
        result = BaseResult()
        req = QueryDict(request.body)
        Question.objects.get(pk=req.get('id')).delete()
        result.success = True
        return JsonResponse(result.toJSON())

同PUT一样,delete请求的参数也需要通过body转dict再get获取

$ curl http://127.0.0.1:8000/polls/question/ -X DELETE -d 'id=3'

{"success": true, "error": null}  

结束

自此一个非常简单的CURD就结束了,当然这不能体现django的流行和强大,仅仅作为一个入门路线,基于此再去扩展尝试django其他特性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值