组件化开发

适合简单地增删改查
不适合生成此处的复杂交易功能
from django import forms
from django.contrib import messages
from django.shortcuts import render, redirect
from django.core.exceptions import ValidationError

from utils.v3 import BaseCurd
from app01 import models
from utils.encrypt import md5
from utils.boostrap import BootStrapForm


class ResetPasswordModelForm(BootStrapForm, forms.ModelForm):
    confirm_password = forms.CharField(
        label="重复密码",
        widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
        model = models.Customer
        fields = ['password', 'confirm_password', ]
        widgets = {
            'password': forms.PasswordInput(render_value=True),
        }

    def clean_password(self):
        password = self.cleaned_data['password']
        return md5(password)

    def clean_confirm_password(self):
        password = self.cleaned_data.get('password')
        confirm_password = md5(self.cleaned_data.get('confirm_password', ''))

        if password != confirm_password:
            raise ValidationError("密码不一致")
        return confirm_password


class Info2(BaseCurd):

    def list(self, request):
        # 获取当前用户信息
        instance = models.Customer.objects.filter(id=request.nb_user.id, active=1).first()
        if request.method == "GET":
            # 生成Form表单
            form = ResetPasswordModelForm()
            context = {"instance": instance, 'form': form}
            return render(request, 'user2/info_list.html', context)

        form = ResetPasswordModelForm(instance=instance, data=request.POST)
        if not form.is_valid():
            context = {"instance": instance, 'form': form}
            return render(request, 'user2/info_list.html', context)

        form.save()
        messages.add_message(request, messages.SUCCESS, "更新成功")
        return redirect("info2_list")

订单刷播放项目的回顾七,组件化开发功能,订单相关操作_html

组件-订单显示列

时间处理

v3.py

def get_datetime_field(field, fmt):
    def inner(request, instance):
        return getattr(instance, field).strftime(fmt)

    return inner

订单刷播放项目的回顾七,组件化开发功能,订单相关操作_ide_02

状态,数字转中文
def get_choice_field(field):
    def inner(request, instance):
        # 对象.get_field_display  ()
        # return getattr(instance, field).strftime(fmt)
        return getattr(instance, f"get_{field}_display")()

    return inner
撤单
def get_cancel_btn(request, instance):

        if instance.status == 1:
            # return mark_safe(f"<a class='btn btn-danger btn-xs' href='/yang2/cancel/{instance.pk}/'>撤单</a>")
            # prev = reverse("yang2_cancel", kwargs={"pk": instance.pk})
            # current_url = request.get_full_path()
            # param = quote_plus(current_url)
            # url = f"{prev}?redirect={param}"
            url = gen_url(request, "yang2_cancel", kwargs={"pk": instance.pk})
            return mark_safe(f"<a class='btn btn-danger btn-xs' href='{url}'>撤单</a>")
        return ""

订单刷播放项目的回顾七,组件化开发功能,订单相关操作_ide_03

创建订单

yang2.py

def add_save(self, form, request):
        # self.request
        # form.save()
        video_url = form.cleaned_data['url']
        count = int(form.cleaned_data['count'])

        # 1.原视频播放量采集
        status, view_count = get_old_view_count(video_url)
        if not status:
            form.add_error("url", "视频原播放量采集失败")
            return render(request, self.add_template, {"form": form})

        # 2.订单号
        while True:
            ctime = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")
            rand_number = random.randint(10000000, 99999999)
            oid = f"{ctime}{rand_number}"
            exists = models.Order.objects.filter(oid=oid).exists()
            if not exists:
                break

        # 3.价格
        for df_count, df_price in form.price_count_list:
            if count >= df_count:
                total_price = round(df_price / df_count * count, 2)
                break

        try:
            with transaction.atomic():
                cus_object = models.Customer.objects.filter(id=request.nb_user.id).select_for_update().first()
                real_price = round(total_price * cus_object.level.percent / 100, 2)
                if cus_object.balance < real_price:
                    form.add_error("count", f"账户余额不足,余额:{cus_object.balance},当前订单价格:{real_price}")
                    return render(request, self.add_template, {"form": form})

                # 创建订单
                form.instance.old_view_count = view_count
                form.instance.oid = oid
                form.instance.price = total_price
                form.instance.real_price = real_price
                form.instance.customer_id = request.nb_user.id
                form.save()

                # 客户账户扣款
                models.Customer.objects.filter(id=request.nb_user.id).update(balance=F("balance") - real_price)

                # 生成交易记录
                models.TransactionRecord.objects.create(
                    charge_type=3,
                    customer_id=request.nb_user.id,
                    amount=real_price,
                    order_oid=oid
                )

                # 将订单号加入队列(redis)    ->   [元素,]   ->
                conn = get_redis_connection("default")
                conn.lpush("nb_task_queue", oid)
        except Exception as e:
            form.add_error("count", "订单创建失败")
            return render(request, self.add_template, {"form": form})

订单刷播放项目的回顾七,组件化开发功能,订单相关操作_Customer_04

撤单
def cancel(self, request, pk):
        origin = request.GET.get("redirect", "/home/")
        order_object = models.Order.objects.filter(id=pk, active=1, status=1, customer_id=request.nb_user.id).first()

        # 订单不存在,或已经撤单
        if not order_object:
            # message发送错误信息
            messages.add_message(request, settings.MESSAGE_DANDER_TAG, "订单不存在")
            return redirect(origin)

        # 撤单
        try:
            with transaction.atomic():
                models.Customer.objects.filter(id=request.nb_user.id).select_for_update()

                # 1.订单状态变已撤单
                models.Order.objects.filter(id=pk, active=1, status=1, customer_id=request.nb_user.id).update(status=5)

                # 2.归还余额
                models.Customer.objects.filter(id=request.nb_user.id).update(
                    balance=F("balance") + order_object.real_price)

                # 3.交易记录(撤单)
                models.TransactionRecord.objects.create(
                    charge_type=5,
                    customer_id=request.nb_user.id,
                    amount=order_object.real_price,
                    order_oid=order_object.oid
                )

                # 提示
                messages.add_message(request, messages.SUCCESS, "撤单成功")
                return redirect(origin)
        except Exception as e:
            messages.add_message(request, settings.MESSAGE_DANDER_TAG, f"撤单失败,{e}")
            return redirect(origin)
我的交易记录
class Yang2(BaseCurd):
    # list_template_name = "v3/list.html"

    table_header = ["日期", "订单号", "URL", "数量", "价格", "实际价格", "原播放", "状态", "备注", "撤单"]

    def get_cancel_btn(request, instance):

        if instance.status == 1:
            # return mark_safe(f"<a class='btn btn-danger btn-xs' href='/yang2/cancel/{instance.pk}/'>撤单</a>")
            # prev = reverse("yang2_cancel", kwargs={"pk": instance.pk})
            # current_url = request.get_full_path()
            # param = quote_plus(current_url)
            # url = f"{prev}?redirect={param}"
            url = gen_url(request, "yang2_cancel", kwargs={"pk": instance.pk})
            return mark_safe(f"<a class='btn btn-danger btn-xs' href='{url}'>撤单</a>")
        return ""

    table_field = [
        # ("db", "create_datetime"),
        # ("func", get_create_date),
        ("func", get_datetime_field("create_datetime", "%Y-%m-%d %H:%M:%S")),
        ("db", "oid"),
        ("db", "url"),
        ("db", "count"),
        ("db", "price"),
        ("db", "real_price"),
        ("db", "old_view_count"),
        # ("db", "status"),
        # ("func", get_status),
        ("func", get_choice_field("status")),
        ("db", "memo"),
        ("func", get_cancel_btn),
    ]

    def get_queryset(self, request):
        return models.Order.objects.filter(customer_id=request.nb_user.id).order_by("-id")

    search_list = ["oid__contains", "url__contains"]

    add_template = "user2/form.html"
    add_form_class = YangModelForm

    def add_save(self, form, request):
        # self.request
        # form.save()
        video_url = form.cleaned_data['url']
        count = int(form.cleaned_data['count'])

        # 1.原视频播放量采集
        status, view_count = get_old_view_count(video_url)
        if not status:
            form.add_error("url", "视频原播放量采集失败")
            return render(request, self.add_template, {"form": form})

        # 2.订单号
        while True:
            ctime = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")
            rand_number = random.randint(10000000, 99999999)
            oid = f"{ctime}{rand_number}"
            exists = models.Order.objects.filter(oid=oid).exists()
            if not exists:
                break

        # 3.价格
        for df_count, df_price in form.price_count_list:
            if count >= df_count:
                total_price = round(df_price / df_count * count, 2)
                break

        try:
            with transaction.atomic():
                cus_object = models.Customer.objects.filter(id=request.nb_user.id).select_for_update().first()
                real_price = round(total_price * cus_object.level.percent / 100, 2)
                if cus_object.balance < real_price:
                    form.add_error("count", f"账户余额不足,余额:{cus_object.balance},当前订单价格:{real_price}")
                    return render(request, self.add_template, {"form": form})

                # 创建订单
                form.instance.old_view_count = view_count
                form.instance.oid = oid
                form.instance.price = total_price
                form.instance.real_price = real_price
                form.instance.customer_id = request.nb_user.id
                form.save()

                # 客户账户扣款
                models.Customer.objects.filter(id=request.nb_user.id).update(balance=F("balance") - real_price)

                # 生成交易记录
                models.TransactionRecord.objects.create(
                    charge_type=3,
                    customer_id=request.nb_user.id,
                    amount=real_price,
                    order_oid=oid
                )

                # 将订单号加入队列(redis)    ->   [元素,]   ->
                conn = get_redis_connection("default")
                conn.lpush("nb_task_queue", oid)
        except Exception as e:
            form.add_error("count", "订单创建失败")
            return render(request, self.add_template, {"form": form})

    def get_extra_url(self):
        return [
            path(f'cancel/<int:pk>/', self.dispatch(self.cancel), name=f"yang2_cancel")
        ]

    def cancel(self, request, pk):
        origin = request.GET.get("redirect", "/home/")
        order_object = models.Order.objects.filter(id=pk, active=1, status=1, customer_id=request.nb_user.id).first()

        # 订单不存在,或已经撤单
        if not order_object:
            # message发送错误信息
            messages.add_message(request, settings.MESSAGE_DANDER_TAG, "订单不存在")
            return redirect(origin)

        # 撤单
        try:
            with transaction.atomic():
                models.Customer.objects.filter(id=request.nb_user.id).select_for_update()

                # 1.订单状态变已撤单
                models.Order.objects.filter(id=pk, active=1, status=1, customer_id=request.nb_user.id).update(status=5)

                # 2.归还余额
                models.Customer.objects.filter(id=request.nb_user.id).update(
                    balance=F("balance") + order_object.real_price)

                # 3.交易记录(撤单)
                models.TransactionRecord.objects.create(
                    charge_type=5,
                    customer_id=request.nb_user.id,
                    amount=order_object.real_price,
                    order_oid=order_object.oid
                )

                # 提示
                messages.add_message(request, messages.SUCCESS, "撤单成功")
                return redirect(origin)
        except Exception as e:
            messages.add_message(request, settings.MESSAGE_DANDER_TAG, f"撤单失败,{e}")
            return redirect(origin)

订单刷播放项目的回顾七,组件化开发功能,订单相关操作_html_05

管理员-级别管理

# 基于定义实现
class LevelModelForm(object):
    name = "admin"
    salary = 19000

    def func(self):
        return 123


# 基于创建类
LevelModelForm2 = type("LevelModelForm2", (object,), {"name": "admin", "salary": 19000, "func": lambda self: 123})

obj = LevelModelForm2()
res = obj.func()
print(res)

print(LevelModelForm().func())


123
123


#或者
from django import forms

from utils.boostrap import BootStrapForm
#
# # ######### 案例2 #########
meta_cls = type("Meta", (object,), {"model": 123, "fields": [1122]})
model_form_cls = type("LevelModelForm", (BootStrapForm, forms.ModelForm), {"Meta": meta_cls})

views/backhend/level.py

from django.contrib import messages

from app01 import models
from utils.v3 import BaseCurd


class Level(BaseCurd):
    # 列表配置
    queryset = models.Level.objects.filter(active=1).order_by("percent")
    table_header = ["级别", "折扣"]
    table_field = [
        ("db", "title"),
        ("func", lambda req, ins: f"{ins.percent}%"),
    ]

    #  新增和编辑配置
    base_form_model = models.Level
    base_form_fields = ["title", "percent"]

    # # 新增配置
    # add_template = "v3/form.html"
    # add_form_model = models.Level
    # add_form_fields = ["title", "percent"]
    #
    # # 编辑配置
    # edit_template = "v3/form.html"
    # edit_form_model = models.Level
    # edit_form_fields = ["title", "percent"]

    # 删除
    def do_delete(self, request, pk):
        models.Level.objects.filter(active=1, id=pk).update(active=0)
        messages.add_message(request, messages.SUCCESS, "删除成功")

价格管理

price.py

from app01 import models
from utils.v3 import BaseCurd


class Price(BaseCurd):
    # 列表配置
    queryset = models.PricePolicy.objects.filter().order_by("count")
    table_header = ["数量", "价格"]
    table_field = [
        ("db", "count"),
        ("func", lambda req, ins: f"¥{ins.price}"),
    ]

    #  新增和编辑配置
    base_form_model = models.PricePolicy
    base_form_fields = ["count", "price"]

客户管理

from django import forms
from django.urls import path
from django.shortcuts import render, redirect
from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe


from app01 import models
from utils.boostrap import BootStrapForm
from utils.v3 import BaseCurd, get_datetime_field, gen_url, Option
from utils.encrypt import md5


class CustomerModelForm(BootStrapForm, forms.ModelForm):
    exclude_field_list = ['level']

    confirm_password = forms.CharField(
        label="重复密码",
        widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
        model = models.Customer
        fields = ['level', "username", 'mobile', 'password', 'confirm_password', ]
        widgets = {
            'password': forms.PasswordInput(render_value=True),
            "level": forms.RadioSelect(attrs={'class': "form-radio"})
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # self.fields['level'].queryset = models.Level.objects.filter(active=1)

    def clean_password(self):
        password = self.cleaned_data['password']

        return md5(password)

    def clean_confirm_password(self):
        password = self.cleaned_data.get('password')
        confirm_password = md5(self.cleaned_data.get('confirm_password', ''))

        if password != confirm_password:
            raise ValidationError("密码不一致")
        return confirm_password


class CustomerEditModelForm(BootStrapForm, forms.ModelForm):
    exclude_field_list = ['level']

    class Meta:
        model = models.Customer
        fields = ['level', "username", 'mobile', ]
        widgets = {
            "level": forms.RadioSelect(attrs={'class': "form-radio"})
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


class CustomerResetModelForm(BootStrapForm, forms.ModelForm):
    confirm_password = forms.CharField(
        label="重复密码",
        widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
        model = models.Customer
        fields = ['password', 'confirm_password', ]
        widgets = {
            'password': forms.PasswordInput(render_value=True),
        }

    def clean_password(self):
        password = self.cleaned_data['password']

        return md5(password)

    def clean_confirm_password(self):
        password = self.cleaned_data.get('password')
        confirm_password = md5(self.cleaned_data.get('confirm_password', ''))

        if password != confirm_password:
            raise ValidationError("密码不一致")
        return confirm_password


class Customer(BaseCurd):
    # 客户列表,表格配置
    queryset = models.Customer.objects.filter(active=1).order_by("-id")
    table_header = ["用户名", "手机号", "余额", "级别", "创建日期", "重置密码"]

    def get_reset(request, instance):
        url = gen_url(request, "customer_reset", kwargs={"pk": instance.pk})
        return mark_safe(f"<a href='{url}'>重置密码</a>")

    table_field = [
        ("db", "username"),
        ("db", "mobile"),
        ("db", "balance"),
        ("func", lambda req, ins: f"{ins.level.title}({ins.level.percent}%折扣)"),
        ("func", get_datetime_field("create_date", "%Y-%m-%d")),
        ("func", get_reset)
    ]

    # 组合搜索
    search_group = [
        models.Customer,
        Option("level", False, {"active": 1}),
        Option("creator", False),
        Option("gender", is_choice=True),
        # Option("mobile", db_condition={"id__lte": 4}, text_func=lambda x: x.mobile, value_func=lambda x: x.mobile),
    ]
    # 关键字搜索
    search_list = ["username", "mobile__contains"]

    # 创建ModelForm
    add_template = "v3/form.html"
    add_form_class = CustomerModelForm

    def add_save(self, form, request):
        form.instance.creator_id = request.nb_user.id
        form.save()

    # 编辑
    edit_template = "v3/form.html"
    edit_form_class = CustomerEditModelForm

    # 删除
    def do_delete(self, request, pk):
        models.Customer.objects.filter(active=1, id=pk).update(active=0)

    # 重置密码
    def get_extra_url(self):
        return [
            path(f'reset/<int:pk>/', self.dispatch(self.reset), name=f"customer_reset")
        ]

    def reset(self, request, pk):
        origin = request.GET.get("redirect", "/home/")

        if request.method == "GET":
            form = CustomerResetModelForm()
            return render(request, "v3/form.html", {"form": form})

        instance = models.Customer.objects.filter(id=pk, active=1).first()
        form = CustomerResetModelForm(data=request.POST, instance=instance)
        if not form.is_valid():
            return render(request, 'v3/form.html', {'form': form})

        form.save()
        return redirect(origin)

交易记录

充值与扣款

records.py

from django.urls import reverse
from django import forms
from django.db import transaction
from django.db.models import F
from django.shortcuts import render
from django.utils.safestring import mark_safe


from app01 import models
from utils.boostrap import BootStrapForm
from utils.v3 import BaseCurd, get_datetime_field, get_choice_field, Option


class TransactionRecordModelForm(BootStrapForm, forms.ModelForm):
    charge_type = forms.TypedChoiceField(
        label="交易类型",
        choices=[(1, "充值"), (2, "扣款")],
        coerce=lambda val: int(val)
    )

    class Meta:
        model = models.TransactionRecord
        fields = ["customer", "charge_type", "amount"]


class Record(BaseCurd):
    # 列表配置
    queryset = models.TransactionRecord.objects.all().order_by("-id")

    table_header = ["日期", "客户", "金额", "交易类型", "订单号", "管理员"]

    def get_order_oid(request, instance):
        if instance.order_oid:
            url = reverse("yang2_list")
            return mark_safe(f'<a href="{url}?keyword={instance.order_oid}">订单号:{instance.order_oid}</a>')
        return "-"

    table_field = [
        # ("db", "create_datetime"),
        ("func", get_datetime_field("create_datetime", "%Y-%m-%d")),
        # ("db", "customer"),
        ("func", lambda req, ins: ins.customer.username),
        ("func", lambda req, ins: f"-{ins.amount}" if ins.charge_type in [2, 3] else f"+{ins.amount}"),
        ("func", get_choice_field("charge_type")),
        ("func", get_order_oid),
        # ("func", lambda req, ins: ins.creator if ins.creator else ""),
        ("func", lambda req, ins: ins.creator or ""),
    ]

    # 组合搜索
    search_group = [
        models.TransactionRecord,
        Option("charge_type", is_choice=True),
        Option("customer", False, db_condition={"active": 1}),
    ]

    # 关键字
    search_list = ["customer__username__contains", "order_oid__contains"]

    #  新增和编辑配置
    add_template = "v3/form.html"
    # add_form_model = models.TransactionRecord
    # add_form_fields = ["customer", "charge_type", "amount"]
    add_form_class = TransactionRecordModelForm

    def add_save(self, form, request):
        # 用户余额增加或减少
        customer = form.cleaned_data['customer']
        charge_type = form.cleaned_data['charge_type']
        amount = form.cleaned_data['amount']
        if amount < 0:
            form.add_error("amount", "金额不能小于零")
            return render(request, self.add_template, {"form": form})

        try:
            with transaction.atomic():
                if charge_type == 1:
                    models.Customer.objects.filter(id=customer.id).update(balance=F("balance") + amount)
                else:
                    models.Customer.objects.filter(id=customer.id).update(balance=F("balance") - amount)

                # 创建交易记录
                form.instance.creator_id = request.nb_user.id
                form.save()
        except Exception as e:
            form.add_error("amount", "新增失败")
            return render(request, self.add_template, {"form": form})