【用django2.0来开发】 后台会员管理

【用django2.0来开发】 后台会员管理

项目地址:https://gitee.com/ccnv07/django_example
这一篇主要是要完成django 后台的会员管理功能, 会涉及到model, ModelAdmin, admin, Form等多个方面, 所以会讲的比较细

创建会员模块

cd cms
python manage.py startapp account

python manage.py startapp 是创建一个模块

至于模块的定义, 每个人都有不同的看法, 有些是按照功能来划分的, 比如会员模块, 订单模块等, 有些是按照不同场景划分的, web端, api, wap端等。这个无所谓, 咱们的项目是按照功能来划分

注册到项目中, 因为django的模块是可插拔的, 所以每个需要的模块都要在cms/settings.py中注册

# cms/settings.py
INSTALLED_APPS = [
    ‘django.contrib.admin‘,
    ‘django.contrib.auth‘,
    ‘django.contrib.contenttypes‘,
    ‘django.contrib.sessions‘,
    ‘django.contrib.messages‘,
    ‘django.contrib.staticfiles‘,
    ‘account‘ # 添加了我们刚创建的account
]

创建Model

通过django的model, 可以直接操作数据库的表结构等
打开account/models.py, 创建一个Account模型

account = models.CharField(max_length=64, blank=True, verbose_name=‘用户名‘)
account: 字段名
models.CharField: 指定字段类型是char, 对应到数据库是varchar
max_length: 是字段长度
blank: 是否可以为空
verbose_name: 控制的是后台列表的展示

除此之外, 常见的字段选项还有
null: 字段的值是否可以是null, 设置为True是可以
choices: 字段的选项值, 一般会影响后台列表和编辑, form表单中字段的显示

status = models.IntegerField(
        default=1, blank=True, verbose_name=‘状态‘, choices=((1, ‘启用‘), (0, ‘禁用‘)))
# 这个choices=((值, 显示名),)

default: 默认值, 字段不存在时的插入
unique: 是否唯一
auto_now_add: DateTime和Date字段专属, 新增时自动插入时间
auto_now: 同auto_now_add, 但是是在任何变更时都变化, 如果存在auto_now, 就不用设置auto_now_add, 否则django提示你两个不能共存。

Model数据迁移操作

基本操作流程:

  1. 创建迁移文件
  2. 执行迁移
python manage.py makemigrations

会有类似以下的提示

这一步其实还没有迁移到数据库, 只是创建了迁移文件, 在account/migrations目录下, 打开就会发现是python的类

接下来执行迁移

python manage.py migrate


说明迁移成功

将Model注册到Admin后台中

注册后, 才能在后台看到相应的管理

# account/admin.py
from django.contrib import admin
from django.db import models
from .models import Account

admin.site.register(Account)

预览看看

先运行测试服务器 python manage.py runserver
在浏览器中输入http://127.0.0.1:8000/admin

但是可能你看到的是英文的, 所以先将语言和时间本地化

# cms/settings.py
LANGUAGE_CODE = ‘zh-Hans‘
TIME_ZONE = ‘PRC‘

然后刷新, 就可以看到变成中文了, 但是Accounts那个还是英文, 挺丑的

# account/models.py
class Account(model.Model):
    ...忽略代码
    class Meta:
        ordering = [‘-id‘]
        verbose_name = ‘会员‘  # 指定在后台列表、添加、编辑等其他非菜单页显示的名称, 但是后面会加s
        verbose_name_plural = ‘会员管理‘  # 指定后台菜单显示的名称, 不会加s

修改管理界面的展示

# account/admin.py
from django.contrib import admin
from django.db import models
from .models import Account

@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    date_hierarchy = ‘create_time‘
    # 控制列表页按钮显示位置
    actions_on_top = False
    actions_on_bottom = True

    # 是否显示列表页数据数量([选中了n个中的m个])
    actions_selection_counter = True

    # 控制新增、编辑页面显示的字段
    fields = (‘account‘, ‘nickname‘, ‘password‘, ‘email‘, ‘phone‘, ‘status‘)

    # 排除新增、编辑页面要显示的字段
    # exclude = (‘password‘, )

    # 控制列表页显示的字段
    list_display = (‘account‘, ‘nickname‘, ‘email‘, ‘phone‘, ‘status‘,
                    ‘create_time‘)
    list_display_links = (‘account‘, )

    # 指定字段是否可以在列表页直接编辑
    list_editable = (‘status‘, )

    # 列表页过滤条件
    list_filter = (‘status‘, )

    # 控制每页显示数量
    # list_per_page = 1

    # 列表页排序
    ordering = [‘-id‘]
    # 自定义操作
    actions = [‘make_published‘, ‘deleted_select‘]

这一块都是一些配置项, 大家可以直接复制, 然后一点点屏蔽了试试

修改默认操作

还记得我们有一个is_deleted字段么? 可以回头看看AccountModel. 因为django后台的删除时直接删掉数据, 而我们要做到的操作是删除数据就更新is_deleted字段为1

# account/admin.py
# 这个会直接将整个模块的删除操作都禁用掉
# 禁用默认的删除操作
admin.site.disable_action(‘delete_selected‘)

# 重写增加一个删除操作
def deleted_select(self, request, queryset):
    queryset.update(is_deleted=1)

# 将操作添加进去并指定显示名称
admin.site.add_action(deleted_select, ‘删除所选会员‘)

同样的, 我们有一个status字段, 希望可以在列表中直接多选, 将用户禁用和启用

# 还是account/admin.py
# 这个操作可能只有会员管理有, 所以我们可以定在AccountAdmin中
@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    def stop_account(self, request, queryset):
        queryset.update(status=0)
    stop_account.short_description = "禁用"

    def start_account(self, request, queryset):
        queryset.update(status=1)
    start_account.short_description = ‘启用‘

然后刷新页面就可以看到

现在我们创建个会员, 点击增加 会员+按钮, 输入指定的信息, 然后点击添加, 就会在列表显示
多增加几个
然后回到列表, 删除其中一个会员, 然后惊奇的发现, 我去, 为啥还会展示出来呢? 因为我们定义的删除是is_deleted=1, 而django默认的删除时真正的删除操作, 所以还是会显示出来
那么, 怎么办呢?

# 还是account/admin.py
@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    # 过滤显示的数据, 只显示is_deleted=0的数据
    # 这个方法可以指定数据的查询条件
    # queryset就是获取到查询对象, filter()是指定查询is_deleted=0的数据
    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.filter(is_deleted=0)

然后刷新页面, 就发现执行过删除操作的数据没有了

我还想更改字段新增编辑时的表单

然后我们也发现了几个新的问题

  1. 密码输入框居然是明文的
  2. 新增编辑时的验证条件也不符合我的要求阿
  3. 编辑会员信息时, 如果密码框为空, 就会把密码清空, 这太恐怖了

针对这几个问题, 我们就得创建一个ModelForm来控制表单了

# 创建个account/forms.py
# -*- coding: utf-8 -*-
from django import forms
from django.db.models import Q
from django.core.exceptions import ValidationError
from django.contrib.auth.hashers import make_password
from .models import Account

class AccountForm(forms.ModelForm):
    account = forms.CharField(required=True, error_messages={
            ‘required‘: ‘请输入用户名‘,
        }, label=‘用户名‘)
    password = forms.CharField(
        # 指定密码字段使用password输入框
        widget=forms.PasswordInput(),
        max_length=12,
        min_length=6,
        strip=True,
        error_messages={
            ‘max_length‘: ‘最大长度不可超过12个字符‘,
            ‘min_length‘: ‘最小长度不可少于6个字符‘
        },
        required=False,
        label=‘密码‘)
    email = forms.EmailField(
        required=True, error_messages={‘required‘: ‘请输入邮箱‘}, label=‘邮箱‘)
    phone = forms.CharField(
        required=True,
        error_messages={‘required‘: ‘请输入手机号‘},
        label=‘手机号‘)
    status = forms.ChoiceField(
        choices=((1, ‘启用‘), (0, ‘禁用‘)), label=‘用户状态‘)

    class Meta:
        # 指定关联的model
        model = Account
        # 使用自定义的Form, 就必须指定fields or exclude属性, 否则报错
        fields = (‘account‘, ‘password‘, ‘email‘, ‘phone‘, ‘status‘)

最上面的几个类属性 account,email,phone,status等, 都是指定表单的字段
required: 字段必须输入
error_messages: 指定错误提示信息
label: 是在表单中显示的中文名
help_text: 显示字段的帮助信息
max_length和min_length: 指定字段输入的最大/最小长度
strip: 自动过滤空

然后在AccountAdmin中指定使用的form

# account/admin.py
from .forms import AccountForm
@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    ... 忽略代码
    form = AccountForm

然后就可以使用了, 但是其他验证的条件我们如何来做呢?
先重写AccountAdmin.get_form方法

@admin.register(Account)
class AccountAdmin(admin.ModelAdmin):
    ... 忽略代码
    def get_form(self, request, obj=None, **kwargs):
        form = super(AccountAdmin, self).get_form(request, obj=obj, **kwargs)

        # obj 保存的是models.Account的信息
        # 根据是否有pk, 来赋予form不同的场景, 根据不同的场景可以进行不同的验证
        if (hasattr(obj, ‘pk‘)):
            form.id = obj.pk
            form.scene = ‘update‘
        else:
            form.scene = ‘insert‘
        return form

然后在form中自定义验证规则

# -*- coding: utf-8 -*-
from django import forms
from django.db.models import Q
from django.core.exceptions import ValidationError
from django.contrib.auth.hashers import make_password
from .models import Account

class AccountForm(forms.ModelForm):
    ... 忽略代码
    def clean_account(self):
        # 自动验证account字段, 判断用户名是否唯一
        # self.scene 是AccountAdmin.get_form中定义的
        if self.scene == ‘insert‘:
            _info = Account.objects.filter(
                email=self.cleaned_data[‘account‘], is_deleted=0).values(‘id‘)
        elif self.scene == ‘update‘:
            _info = Account.objects.filter(
                ~Q(id=self.id),
                email=self.cleaned_data[‘account‘],
                is_deleted=0).values(‘id‘)

        if _info:
            raise ValidationError(‘用户已存在‘)
        return self.cleaned_data[‘account‘]

    def clean_password(self):
        # 自动验证密码字段
        if self.scene == ‘insert‘:
            if not self.cleaned_data[‘password‘]:
                raise ValidationError(‘请输入密码‘)
        elif self.scene == ‘update‘:
            if not self.cleaned_data[‘password‘]:
                return None
            else:
                return self.cleaned_data[‘password‘]
        return make_password(self.cleaned_data[‘password‘])

    def clean_email(self):
        # 自动验证email字段
        if self.scene == ‘insert‘:
            _info = Account.objects.filter(
                email=self.cleaned_data[‘email‘], is_deleted=0).values(‘id‘)
        elif self.scene == ‘update‘:
            _info = Account.objects.filter(
                ~Q(id=self.id), email=self.cleaned_data[‘email‘],
                is_deleted=0).values(‘id‘)

        if _info:
            raise ValidationError(‘邮箱已存在‘)

        return self.cleaned_data[‘email‘]

    def clean_phone(self):
        if self.scene == ‘insert‘:
            _info = Account.objects.filter(
                email=self.cleaned_data[‘phone‘], is_deleted=0).values(‘id‘)
        elif self.scene == ‘update‘:
            _info = Account.objects.filter(
                ~Q(id=self.id), email=self.cleaned_data[‘phone‘],
                is_deleted=0).values(‘id‘)

        if _info:
            raise ValidationError(‘手机号已存在‘)
        return self.cleaned_data[‘phone‘]

clean_字段名定义关于某个字段的自定义方法, 验证失败, 可以使用raise ValidateError抛出错误, 验证成功, 需要返回一个值, form会赋值为model, 接着进行后续的新增/编辑操作

然后刷新页面尝试下, 发现其他的问题都解决了, 但是编辑时密码为空还是无法解决
这时我们可以重写AccountAdmin.save_model方法, 来达到我们的目的

# account/admin.py
class AccountAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        # 如果form验证完成后赋值给obj的password字段是None, 则删除密码字段, 不进行更新
        if form.cleaned_data[‘password‘] is None:
            del obj.password
        super().save_model(request, obj, form, change)

好了, 至此, 我们的后台会员管理功能就做完了。

原文地址:http://blog.51cto.com/a3147972/2306756

时间: 2024-08-08 20:31:17

【用django2.0来开发】 后台会员管理的相关文章

一、【用django2.0来开发】 环境部署和初始化项目

一.[用django2.0来开发] 环境部署和初始化项目 发现网上没有什么比较好的django系列的教程, 所以打算写一整套教程来教会大家如何使用django2.0 整个教程都会围绕一个开发一个项目来完成, 这一篇主要就是讲清楚整个环境以及初始化下项目, 以及一些开发中常见的操作项目地址:https://gitee.com/ccnv07/django_example 项目介绍 大概就是使用python开发一个cms系统, 和大家知道的dede,phpcms有些类似, 可以注册.登录.有会员系统.

解决Python3.6.5+Django2.0集成xadmin后台点击添加或者内容详情报 list index out of range 的错误

一 问题说明在创建Model的时候,如果存在类型是DateTimeField的字段,则在xadmin后端管理界面里,对该Model进行添加操作的时候,会报list index out of range. 这是上篇文章创建的Model: class IDC(models.Model): name = models.CharField(max_length=64) contact = models.CharField(max_length=32) phone = models.CharField(m

四【用django2.0来开发】后台会员管理(二) ModelForm表单的使用方法以及数据验证

上一节我们讲完了ModelAdmin的使用, 但是在操作中也发现, 新增编辑会员时, 我们无法验证数据是否正确, 比如 用户名.手机号.邮箱都应该是唯一的 用户名和密码长度的验证 编辑用户信息时不填写密码则不更新密码, 填写了则更新密码 自定义验证不通过的文案... 这些要求, 我们就必须得使用自定义的表单来完成了 项目地址:https://gitee.com/ccnv07/django_example Form介绍 通过表单, 我们可以实现以下的功能 自定义字段的样式 类似的表单可以通过类继承

五 【用django2.0来开发】实现会员注册功能

上一节我们完成了会员功能的后台管理, 这一节我们需要完成会员注册功能, 涉及到以下几个模块 URL配置 views视图模块 模板 Request/Response对象的使用 项目地址:https://gitee.com/ccnv07/django_example URL路由配置 django是通过项目的urls.py文件来定义网站的url路由, 在我们的项目中是cms/urls.py文件 django的基本访问流程 访问url时, 通过cms/urls.py中定义的url路由, 获取到要执行的视

8、Cocos2dx 3.0游戏开发找小三之3.0版本的内存管理

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27693365 复杂的内存管理 移动设备上的硬件资源十分有限,内存尤为宝贵,开发者必须十分慎重地利用内存,避免不必要的消耗,更要防止内存泄漏. 基于 Cocos2d-iPhone 的 Objective-C风格的内存管理是 Cocos2d-x 的一个特色. 把 Objective-C 的内存管理方式引入 C++,使得游戏开发的内存管理难度下降了个层次.

做项目学习Django2.0开发

课程详情可访问:项目学习django2.0.3 项目代码可加qq群:631575625 下载 原文地址:http://blog.51cto.com/13340781/2122185

ace admin java 整合 开发 后台框架,aceadmin_HTML5

获取[下载地址]   QQ: 313596790   [免费支持更新]支持三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]A 代码生成器(开发利器);      增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid

ace admin 整合 开发 后台框架

说明:JAVA SpringMVC+mybatis(oracle 和 mysql) HTML5 全新高大尚后台框架 bootstrap(可换皮肤) 1.支持APP手机应用(android和ios)接口调用 2.全新高大尚HTML5+css3.0+bootstrap开发界面UI,美观漂亮时尚.前沿(自动适配PC.平板.手机(需求微调)屏幕) 3.有ORACLE 和MYSQL ,Spring3.0,4.0版本各一个,一共4套版本全部提供的是源代码 4.框架搭建完善,在此基础上做过很多项目,身经百战,

ace admin java 整合 开发 后台框架,aceadmin_HTML5 java springmvc

获取[下载地址]   QQ: 313596790   [免费支持更新]支持三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]A 代码生成器(开发利器);      增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid