动态创建Django视图是不是很糟糕?

时间:2018-03-15 08:39:22

标签: django django-models django-forms django-views

我想为我的应用中的每个模型添加一个通用的创建表单。在反复重复相同的几行之后,仅改变模型名称,DRY原则向我发出呼叫。我想出了以下方法,为我的应用程序中的每个模型动态添加表单,视图和路径。

forms.py

from django import forms
from . import models
import inspect
from django.db.models.base import ModelBase

# Add ModelForm for each model
for name, obj in inspect.getmembers(models):
    if inspect.isclass(obj) and isinstance(obj, ModelBase):
         vars()[name + "ModelForm"] = forms.modelform_factory(obj, exclude=())

views.py

from . import forms
from . import models
import inspect
from django.db.models.base import ModelBase

def form_factory(request, form_type, form_template, redirect_url='index', save=True):
    if request.method == "POST":
        form = form_type(request.POST)
        if form.is_valid():
            if save:
                form.save()
            return HttpResponseRedirect(reverse(redirect_url))
    else:
        form = form_type()
    return render(request, form_template, {'form': form})

# Add view for each model
for name, obj in inspect.getmembers(models):
    if inspect.isclass(obj) and isinstance(obj, ModelBase):
        form = getattr(forms, name + "ModelForm")
        func = lambda request: form_factory(request, form, 'core/create.html')
        name = 'create_' + name.lower()
        vars()[name] = func

urls.py

from django.urls import path
from . import views
from . import models
import inspect
from django.db.models.base import ModelBase

existing_urls = []
for urlpattern in urlpatterns:
    existing_urls.append(urlpattern.pattern._route)

# Add url for each model
for name, obj in inspect.getmembers(models):
    if inspect.isclass(obj) and isinstance(obj, ModelBase):
        name = name.lower()
        url = name + '/new'
        if url in existing_urls:
            continue
        view = getattr(views, 'create_' + name)
        url_name = 'create-' + name
        urlpatterns.append(path(url, view, name=url_name))

这是个坏主意吗?这感觉不对,但我想不出任何具体的理由不这样做。

2 个答案:

答案 0 :(得分:1)

我无法真正看到这种复杂程度的重点。

form_factory与具体的通用视图一样,它接受参数并直接从URL调用。然后可以简化URLconf以迭代模型,并为每个通过这些参与者的模板添加模式。

然后,您可以使用实际的通用视图进一步简化操作。这些可以直接在URLconf中实例化,而无需在views.py中定义子类。而且,CreateView能够自己构建表单,而无需在forms.py中进行定义。所以你可以摆脱这两个文件。

最后一个简化是使用实际的API来获取模型类:django.apps.apps.get_models()。所以你需要的只是:

from django.views.generic.edit import CreateView
from django.apps import apps

for model in apps.get_models():
    urlpatterns += path(
        '{}/new'.format(model._meta.model_name),
        CreateView.as_view(
             model=model,
             template_name='core/create.html',
             fields='__all__',
             success_url=reverse_lazy('index')
        ),
        name='create-{}'.format(model._meta.model_name)
    )

答案 1 :(得分:0)

丹尼尔罗斯曼的答案几乎是正确的,但有一个小错误。动态创建视图的最简单方法是:

from django.views.generic.edit import CreateView
from django.apps import apps

for model in apps.get_app_config('appname').get_models():
    route = path(
        '{}/new'.format(model._meta.model_name),
        CreateView.as_view(
             model=model,
             template_name='core/create.html',
             fields='__all__',
             success_url=reverse_lazy('index')
        ),
        name='create-{}'.format(model._meta.model_name)
    )
    urlpatterns.append(route)

添加get_app_config('appname')可确保只有在所需应用中定义的模型才能获得为其创建的视图。如果没有get_app_config,所有模型都会为它们创建视图,包括django定义的不应该有视图的内容。

使用urlpatterns.append(route)是附加到python列表的正确方法。上一个答案导致错误。

我建议编辑,但它被拒绝了。 =(