django2.0+xadmin2.0d打造权限级管理后台【二】

xadmin权限级店铺系统

  • 继承AbstractUser 控制auth表,这里面有一个问题,密码无法加密,到时候保存密码的时候调用make_password方法
  • from django.contrib.auth.hashers import make_password
  • make_password(password)
  • 做一个店铺表,然后,每一个表都关联店铺表,生成一个店铺字段,表示数据是谁创建的

# 店铺表
class MallShop(AbstractUser):
    name = models.CharField(max_length=20, blank=True, null=True, verbose_name='店铺名')
    openid = models.CharField(max_length=255, verbose_name='openid')
    shop_icon = models.ImageField(upload_to='shop/icon/', blank=True, verbose_name='店铺头像')
    infocode = models.CharField(max_length=20, unique=True, verbose_name='激活码')
    province = models.CharField(max_length=30, blank=True, null=True, verbose_name='省份')
    city = models.CharField(max_length=30, blank=True, null=True, verbose_name='城市')
    quxian = models.CharField(max_length=30, blank=True, null=True, verbose_name='区县')
    address = models.CharField(max_length=300, blank=True, null=True, verbose_name='地址')
    wtchat = models.CharField(max_length=30, blank=True, null=True, verbose_name='微信')
    addtime = models.DateTimeField(auto_now_add=True, verbose_name='激活时间')
    shop_turnover = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='总营业额')
    total_expenditure = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='总支出')
    qrcode = models.CharField(max_length=255, blank=True, verbose_name='二维码', help_text='用户扫码即可成为店铺会员')

    def show_photo(self):
        text = """<img src="%s" style="width:50px;"/>""" % self.shop_icon.url if self.shop_icon else ''
        return mark_safe(text)

    show_photo.short_description = '店铺头像'
    
    

# 用户管理
class MallUser(models.Model):
    shop = models.ForeignKey(to='MallShop', on_delete=models.CASCADE, editable=False, verbose_name='所属店铺')
    level = models.ForeignKey(to='UserClass', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='用户级别')
    openid = models.CharField(max_length=255, verbose_name='openid')
    phone = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    username = models.CharField(max_length=50, default='匿名用户', verbose_name='用户名')
    icon = models.CharField(max_length=255, blank=True, verbose_name='头像')
    gender = models.NullBooleanField(default=None, verbose_name='性别', choices=((None, '不详'), (True, '男'), (False, '女')))
    province = models.CharField(max_length=30, blank=True, null=True, verbose_name='省份')
    city = models.CharField(max_length=30, blank=True, null=True, verbose_name='城市')
    quxian = models.CharField(max_length=30, blank=True, null=True, verbose_name='区县')
    address = models.CharField(max_length=300, blank=True, null=True, verbose_name='地址')
    money = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='余额')
    wechat = models.CharField(max_length=100, blank=True, verbose_name='微信')
    birthday = models.DateTimeField(default=None, blank=True, null=True, verbose_name='生日')
    age = models.CharField(blank=True, max_length=15, verbose_name='年龄')
    addtime = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')
    consumption = models.IntegerField(default=0, verbose_name='消费指数', help_text='平均没人每月来的次数,大于5则高于平均指数,小于则低于平均指数')
    satisfaction = models.IntegerField(default=0, verbose_name='满意度', help_text='根据用户对服务的评价,5为最高,0为最低')

    def over_time_birthday(self):
        if self.birthday:
            month = now.month - self.birthday.month
            day = now.day - self.birthday.day
            if not month:
                text = "<p style='color:red'>会员还剩{}天生日<p/>".format(day)
            else:
                text = "<p style='color:red'>会员还剩{}月{}天生日<p/>".format(month, day)
            return mark_safe(text)
        else:
            return mark_safe("")

    over_time_birthday.short_description = '会员生日'
  • 创建AccessLevel表和ShopUserCreate表,让MallUserAdmin继承他,这样每次创建就保存好是哪个用户创建的,数据加载也只加载该用户创建的,如果还想看见其他人,则重新写过滤
class ShopUserCreate:
    def save_models(self):
        self.new_obj.shop = self.request.user
        super().save_models()


class AccessLevel:

    def get_model(self):
        return self.model_set

    def queryset(self):
        """改进权限级查看"""
        qs = self.request.user
        shopuser = MallShop.objects.get(username=qs)
        if shopuser.is_superuser:
            return self.model._default_manager.get_queryset()
        else:
            return self.get_model().objects.filter(shop=qs)


class MallUserAdmin(AccessLevel, AllowDelete, ShopUserCreate):
    # 设置显示字段
    list_display = ['show_photo', 'shop_username', 'level', 'phone', 'money', 'username', 'gender',
                    'over_time_birthday', 'province', 'city',
                    'quxian', 'address', 'wechat', 'age', 'addtime', 'consumption',
                    'satisfaction', 'ope_balance']
    # 设置搜索字段
    search_fields = ['id', 'phone', 'username']
    # 设置过滤字段
    list_filter = ['gender', 'province', 'city', 'quxian', 'birthday', 'age', 'consumption', 'satisfaction']
    model_icon = 'fa fa-team'
    # list中哪个字段带链接,点击可以进入编辑
    list_display_links = ("phone",)
    # 显示还原按钮,删除修改的信息可以还原
    reversion_enable = True
    #  列聚合,可用的值:"count","min","max","avg",  "sum"
    # aggregate_fields = {"id": "max"}
    show_detail_fields = ['phone']
    show_all_rel_details = True
    # list页面直接编辑
    list_editable = (
        'province', 'city', 'quxian', 'wtchat', 'birthday', 'gender', 'username'
    )
    # 自动刷新
    refresh_times = (3, 5, 10)
    # 添加数据时候,一步一步提供数据
    # wizard_form_list = [
    #     ("基础信息", ("username", "password", "openid", "shop_icon", "infocode")),
    #     ("其它信息", ("last_login", "is_superuser", "name", "province", "city", "quxian", "wtchat")),
    # ]
    # 排序
    ordering = ['-consumption']

    # 不显示字段
    exclude = ['shop']

    is_addbalance = True

    # 自读字段
    readonly_fields = ['satisfaction', 'consumption', 'addtime', 'money', 'icon', 'shop']

    # 添加过滤(这里是过滤日期)
    ate_hierarchy = ['addtime']

    model_set = MallUser

    #  从‘多选框’的形式改变为‘过滤器’的方式,水平排列过滤器,必须是一个 ManyToManyField类型,且不能用于 ForeignKey字段,默认地,管理工具使用`` 下拉框`` 来展现`` 外键`` 字段
    # filter_horizontal = ('authors',)

    def shop_username(self, obj):
        return '%s' % obj.shop.name if obj.shop.name else obj.shop.username  # ☆☆☆☆☆

    shop_username.short_description = '店铺'

    # 重写formfield_for_dbfield,设计add和edit表单
    def formfield_for_dbfield(self, db_field, **kwargs):
        if not self.request.user.is_superuser:
            # 对case这个表项的下拉框选择进行过滤

            if db_field.name == "level":
                kwargs["queryset"] = UserClass.objects.filter(shop=self.request.user).order_by('id')

            # if db_field.user_service == "user_service":
            #     kwargs["queryset"] = UserExpend.objects.filter(shop=self.request.user).order_by('id')
            #
            # if db_field.name == "user_service":
            #     kwargs["queryset"] = UserExpend.objects.filter(shop=self.request.user).order_by('id')
            # 对assigned_recipient这个表项的下拉选择进行过滤
            # 并且需要用到外键
            # if db_field.name == "assigned_recipient":
            #     stu_ids = StudentDoctor.objects.filter(doctor=self.request.user).values('student_id')
            #     ids = []
            #     # 这里使用循环,为了下方再次查询时在list中使用in
            #     for id in stu_ids:
            #         ids.append(id['student_id'])
            #     # 根据主键在ids列表中查询得到Queryset。注意kwargs["queryset"]一定是queryset
            #     kwargs["queryset"] = User.objects.filter(pk__in=ids)
            return db_field.formfield(**dict(**kwargs))

        else:
            attrs = self.get_field_attrs(db_field, **kwargs)
            return db_field.formfield(**dict(attrs, **kwargs))
  • 插件开发
  • 注册插件 然后在你的静态文件下建立 xadmin/js/plug_in_name.js 我这里写的是js插件,然后你去写自己的js文件就行了 is_addbalance = True 表示开启,Flase 表示关闭
class AddBalance(BaseAdminPlugin):
    """给用户增加余额"""
    # 默认不加载,只在需要加载的options中设置True来加载
    is_addbalance = False

    def init_request(self, *arg, **kwargs):
        return self.is_addbalance

    def get_media(self, media):
        # 此处用来加入我们自己的js文件

        media = media + self.vendor("xadmin.self.addbalance.js")
        return media


xadmin.site.register_plugin(AddBalance, ListAdminView)

  • 这里有一个问题 会出来两个提示 我们需要修改一下代码 ## 抱歉,不能这样写,会影响其他的post_response方法,我有比较好的方法, xadmin/views/edit.py 425行代码 直接修改,不要搬到项目下
    在这里插入图片描述
  • 我们找到源码 xadmin/views/edit.py 425行 我们把源码复制到我们的代码里 设置is_msg 如果我们发送了消息 则改成Flase
 @filter_hook
    def post_response(self):
        """
        Determines the HttpResponse for the add_view stage.
        """
        request = self.request

        msg = _(
            'The %(name)s "%(obj)s" was added successfully.') % {
    
    'name': force_text(self.opts.verbose_name),
                                                                 'obj': "<a class='alert-link' href='%s'>%s</a>" % (self.model_admin_url('change', self.new_obj._get_pk_val()), force_text(self.new_obj))}

        if "_continue" in request.POST:
            self.message_user(
                msg + ' ' + _("You may edit it again below."), 'success')
            return self.model_admin_url('change', self.new_obj._get_pk_val())

        if "_addanother" in request.POST:
            self.message_user(msg + ' ' + (_("You may add another %s below.") % force_text(self.opts.verbose_name)), 'success')
            return request.path
        else:
        	# 我们发过了就把 is_msg 改成False,这样系统就不会在调用一次
            if self.is_msg:
                self.message_user(msg, 'success')
            # Figure out where to redirect. If the user has change permission,
            # redirect to the change-list page for this object. Otherwise,
            # redirect to the admin index.
            if "_redirect" in request.POST:
                return request.POST["_redirect"]
            elif self.has_view_permission():
                return self.model_admin_url('changelist')
            else:
                return self.get_admin_url('index')
   

关于xadmin的过滤大家应该也知道,我上面也说了,重写formfield_for_dbfield方法就可以,然后需求来了,inlines里面的内容怎么过滤,我看了一下,光重写formfield_for_dbfield是不行的,然后我追踪源码,查到inlines调用了xadmin/views/edit.py 90行的formfield_for_dbfield方法,然后我就在这个方法里 加上了
if db_field.name == "filename":
 kwargs["queryset"] = model.objects.filter()

然后在导入model,重启一下ok了,我这个提供三种思路,第一个重写源码,第二个改写调用方法,把方法写道adminx.py里,还有就是把整个类提出来重写,我挑了里面最简单,改动最少的。

写完了,关于xadmin也算是有一定了解了项目也已经开源了,有兴趣的可以拿下来看一下
https://github.com/Anning01/shopsystem

猜你喜欢

转载自blog.csdn.net/Python_anning/article/details/95943619
今日推荐