Одна идея состоит в том, чтобы динамически создавать пути. В общем, я бы рекомендовал против этого или, по крайней мере, действовать осторожно - полезно иметь возможность отслеживать, на какие URI отвечает ваше приложение, а ошибки при создании динамического пути c могут привести к раскрытию поведения, которое вы не намеревались. Но поскольку urlpatterns
является чистым Python, вы можете сделать это.
Чтобы сделать это, вам нужен а) способ узнать, какие существуют виды, для которых вы хотите автоматически создавать шаблоны, и б) способ создать экземпляр path
для каждого такого представления.
Для первой части один простой подход состоит в том, чтобы выполнить итерацию возвращаемого значения dir(views_module)
и выполнить фильтрацию на основе некоторых критериев. Например, здесь я собираюсь предположить, что у вас все еще есть предопределенный список моделей, которые вы хотите охватить (как показано в вашем вопросе), и что любой экземпляр представления со значением атрибута model
, который находится в этом списке, потенциально действителен. Вы можете извлечь выгоду из более строгих ограничений, если, скажем, у вас есть специализированные представления, которые вы не хотите включать.
Так что это что-то вроде:
from django.views.generic import CreateView, ListView, DetailView, UpdateView
import views # use your actual module here
model_list = ['company','person','car']
models_to_register = frozenset(model_list)
model_views = [possible_view for possible_view in dir(views) \
if isinstance(possible_view, (CreateView, ListView, DetailView, UpdateView)) \
and getattr(possible_view, 'model', None) in models_to_register]
Тогда вам нужен способ создания path
объекты из каждого вида. У вас уже будет сам объект представления, поэтому вам нужен маршрут и (необязательно, но хорошая идея) имя.
И маршрут, и имя в вашем примере построены, зная операцию, которую реализует представление, и название модели, которую охватывает представление.
Для имени у каждого вида есть атрибут model
, как проверено в понимании списка, поэтому вы можете использовать свойства модели verbose_name
или verbose_name_plural
или определить что-то нестандартное.
Для операции я бы проверил иерархию классов общих c представлений. Так что-то вроде этого:
from django.views.generic import CreateView, ListView, DetailView, UpdateView
def operation_from_model_view(model_view):
if isinstance(model_view, CreateView):
return 'create'
elif isinstance(model_view, ListView):
return 'list'
elif isinstance(model_view, DetailView):
return 'detail'
elif isinstance(model_view, EditView):
return 'update'
else:
# unrecognized view type
return None
def path_from_model_view(model_view):
model_name = model_view.model.verbose_name
operation = operation_from_model_view(model_view)
if not operation or not model_name:
# not expected for name, possible for operation
return None
route = '%s/%s/' % (model_name, operation)
if operation == 'detail' or operation == 'update':
route = route + '<int:pk>/'
path_name = '%s_%s' % (model_name, operation)
return path(route, model_view.as_view(), name=path_name)
Затем добавьте их в свой urlpatterns
, отфильтровывая любые None
s:
urlpatterns = [path for path in (path_from_model_view(view) for view in model_views) \
if path is not None]
Или на 3.8 вы можете использовать "моржа" Оператор присваивания делает что-то вроде urlpatterns = [path for view in model_views if path := path_from_model_view(view) is not None]
.
Это все не проверено - могут быть синтаксические ошибки. И если у вас есть представления, которые являются экземплярами этих четырех базовых представлений в вашем модуле, которые охватывают перечисленные классы моделей, вы зарегистрируете пути к ним - я больше не помню наизусть, является ли это триггером исключения или просто перекрывает старое определение. Если у вас достаточно мало представлений, вы можете захотеть переместить путь из кода представления в собственный миксин и иметь только те представления, которые вы хотите автоматически зарегистрировать, наследуя его - это было бы ближе к явному указанию того, какие URL-адреса ваше приложение предлагает. Но если у вас достаточно мало представлений для этого, у вас может быть мало представлений, чтобы просто перечислить их вручную в вашем urls.py вместо того, чтобы делать что-либо из этого.