gpt4 book ai didi

python - 为复杂的 View 生成器函数定义 API(具有许多可配置项)

转载 作者:太空狗 更新时间:2023-10-29 20:29:44 25 4
gpt4 key购买 nike

我正在为我的 Django 项目编写一个 View 生成器。我有大量来自遗留应用程序的模型(约 150 个模型),它们都需要相同的基本 CRUD 操作(提供管理员访问权限显然是不够的)。

所以我正在编写一个生成器,它为每个模型返回 5 个 View ,当然每个 View 都可能采用大量选项,我正在尝试为我的生成器定义合理的 API/默认参数格式。

我目前的发电机:

def generate_views(model_class, **kwargs):
"""
For a given model, returns a dict of generic class-based views
"""
###
# Forms
# Optionally generate form classes if not already provided
###

# Append these fields with either "create_" or "update_" to have them only
# apply to that specific type of form
form_override_args = ['fields', 'exclude', 'form_method', 'form_class',
'form_layout', 'widgets', 'media_css', 'media_js']

if 'form_class' not in kwargs and 'create_form_class' not in kwargs:
create_form_kwargs = kwargs.copy()
for arg in form_override_args:
if f'create_{arg}' in kwargs:
create_form_kwargs[arg] = kwargs[f'create_{arg}']
kwargs['create_form_class'] = forms.FormFactory(model_class, **create_form_kwargs).form()

if 'form_class' not in kwargs and 'update_form_class' not in kwargs:
update_form_kwargs = kwargs.copy()
for arg in form_override_args:
if f'update_{arg}' in kwargs:
update_form_kwargs[arg] = kwargs[f'update_{arg}']
kwargs['update_form_class'] = forms.FormFactory(model_class, **update_form_kwargs).form()

if 'form_class' not in kwargs:
kwargs['form_class'] = forms.FormFactory(model_class, **kwargs).form()

###
# Tables
# Optionally generate table classes if not already provided
###

# Append these fields with "table_" to have them only
# apply to the table view
table_override_args = ['fields', 'exclude']

if 'table_class' not in kwargs:
update_table_kwargs = kwargs.copy()
for arg in table_override_args:
if f'table_{arg}' in kwargs:
update_table_kwargs[arg] = kwargs[f'table_{arg}']
kwargs['table_class'] = tables.TableFactory(model_class, **update_table_kwargs).table()

###
# Views
# Generate 5 generic views based on the provided model
###
view_factory = views.ViewFactory(model_class, **kwargs)

return {
'list_view': view_factory.list_view(),
'detail_view': view_factory.detail_view(),
'create_view': view_factory.create_view(),
'update_view': view_factory.update_view(),
'delete_view': view_factory.delete_view()
}

我目前依赖于 kwargs,我想定义一个完全填写的 kwargs 字典应该是什么样子。有点像

{
'forms': {
'all': {

},
'create': {

},
'update': {

}
},
'tables': {
'all': {

},
'list': {

}
},
'views': {
'all': {

},
'list': {

},
'detail': {

},
'create': {

},
'update': {

},
'delete': {

}
}
}

而且看起来有点过度劳累。我主要是在寻找有关可能更好的设计的建议(因为我只是在研究它而对它产生了反感)。

最佳答案

看来您正在与 Django 在 class-based views 中构造离散功能/配置的方式作斗争。 .

Django’s generic class-based views are built out of mixins providing discrete functionality.

因此,我的建议是:使用 mixins 将 tableform 类合并到 View 中以进行 CRUD 操作。在生成器中,所有可配置参数都应该只传递给 View

背景知识

让我们看看如何django.views.generic.edit.CreateView被设计。它继承了以下方法和属性: SingleObjectTemplateResponseMixin, BaseCreateViewModelFormMixin。只需几行代码即可将其绑定(bind)到模型:

from myapp.models import Author
class AuthorCreateView(CreateView):
model = Author
fields = ['FirstName','FamilyName','BirthDay']
def form_valid(self, form):
# Saves the form instance, sets the current object for the view, and redirects to get_success_url().

这里 model 属性由所有 mixins 共享以完成它们的工作,而 fieldsform_valid 特定于 ModelFormMixin 。虽然所有可配置的参数/方法都放在 View 类下,但每个 mixin 只是选择它需要的那些。

重新设计 API

牢记这一点,让我们开始简化您的 View 生成器/工厂。对于此示例,假设您有以下包含通用(默认)设置的基类:

from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.views.generic import ListView, DetailView
from django_tables2 as SingleTableMixin

class TableListView(SingleTableMixin, ListView):
table_pagination = { 'per_page': 10 }
# add common configurable parameters here

class MyOwnCreateView(CreateView):
success_url = "/yeah"
# Introduce a configurable method `form_valid_hook`
def form_valid(self, form):
if hasattr(self,'form_valid_hook'):
self.form_valid_hook(form)
return super().form_valid(form)

下面是所有 5 个 View 的简化生成器函数。

BaseViews= {'create': MyOwnCreateView,
'delete': DeleteView,
'update': UpdateView,
'list' : TableListView,
'detail': DetailView }

def generate_views(model_class, **kwargs):
"""
Generate views for `model_class`

Keyword parameters:
{action}=dict(...)
{action}_mixins=tuple(...)
where `action` can be 'list', 'detail', 'create', 'update', 'delete'.
"""
NewViews = {}
for action, baseView in BaseViews.items():
viewName = model_class.__name__ + baseView.__name__
viewAttributes = kwargs.get(action,{})
viewBaseCls = (baseView,) + kwargs.get(f"{action}_mixins",tuple())
v = type(viewName, viewBaseCls, viewAttributes) # create a subclass of baseView
v.model = model_class # bind the view to the model
NewViews[f'{action}_view'] = v
return NewViews

你看,生成器函数被简化为只有 10 行的代码。此外,API 将变得更加简洁:

def validate_author(self, form):
send_email(form)

AuthorViews = generate_views(Author,
create=dict(
success_url='/thanks/',
form_valid_hook=validate_author),
... )

如何在此 API 中使用 mixin

在上面的示例中,我使用钩子(Hook)/回调函数form_valid_hook 在保存表单数据之前注入(inject)一个电子邮件发送过程。这很丑陋,因为电子邮件的可配置项将在模块范围内。最好将其重构为一个 mixin 类。

from django.core.mail import send_mail

class FormEmailMixin:
from_email = 'info@example.com'
subject_template = 'We hear you'
message_template = 'Hi {username}, ...'

def form_valid(self, form):
user_info = dict( username = self.request.user.username
to_email = ... )
send_mail(subject_template.format(**user_info),
message_template.format(**user_info)
self.from_email , [user_info['to_email'],] )
return super().form_valid(form)

然后你就可以在 API 调用中使用这个 mixin 类了。

AuthorViews = generate_views( Author, 
create={ 'message_template': 'Dear Author {username}, ...' },
create_mixins = (FormEmailMixin,) )

关于python - 为复杂的 View 生成器函数定义 API(具有许多可配置项),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55288143/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com