refactor generic url creation
This commit is contained in:
parent
09ff7e82f1
commit
17b9519fa9
@ -1,8 +1,14 @@
|
||||
import re
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import gettext as _
|
||||
from django.db import models
|
||||
|
||||
|
||||
def get_model_name(model):
|
||||
return ('_'.join(re.findall('[A-Z][^A-Z]*', model.__name__))).lower()
|
||||
|
||||
|
||||
class UserPreference(models.Model):
|
||||
# Themes
|
||||
BOOTSTRAP = 'BOOTSTRAP'
|
||||
|
@ -111,9 +111,9 @@
|
||||
class="fas fa-database"></i> {% trans 'Storage Backends' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'data_sync' %}"><i
|
||||
class="fas fa-sync-alt"></i> {% trans 'Configure Sync' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'list_import' %}"><i
|
||||
<a class="dropdown-item" href="{% url 'list_recipe_import' %}"><i
|
||||
class="far fa-file-alt"></i> {% trans 'Import Recipes' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'list_import_log' %}"><i
|
||||
<a class="dropdown-item" href="{% url 'list_sync_log' %}"><i
|
||||
class="fas fa-history"></i> {% trans 'Import Log' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'data_stats' %}"><i
|
||||
class="fas fa-chart-line"></i> {% trans 'Statistics' %}</a>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<h2>{% trans 'Recipe Books' %}</h2>
|
||||
</div>
|
||||
<div class="col col-md-3" style="text-align: right">
|
||||
<a href="{% url 'new_book' %}" class="btn btn-success"><i
|
||||
<a href="{% url 'new_recipe_book' %}" class="btn btn-success"><i
|
||||
class="fas fa-plus-circle"></i> {% trans 'New Book' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
<hr>
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
<a href="{% url 'redirect_delete' form.instance|get_class|lower form.instance.pk %}"
|
||||
<a href="{% delete_url form.instance|get_class form.instance.pk %}"
|
||||
class="btn btn-danger"><i class="fas fa-trash-alt"></i> {% trans 'Delete' %}</a>
|
||||
{% if view_url %}
|
||||
<a href="{{ view_url }}" class="btn btn-info"><i class="far fa-eye"></i> {% trans 'View' %}</a>
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
<h3>{% trans 'Edit' %} {{ title }}</h3>
|
||||
|
||||
{% if form.Meta.model|get_class == 'Storage' %}
|
||||
{% if form.Meta.model|get_class_name == 'Storage' %}
|
||||
{% include 'include/storage_backend_warning.html' %}
|
||||
{% endif %}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
<a href="{% url 'redirect_delete' form.instance|get_class|lower form.instance.pk %}"
|
||||
<a href="{% delete_url form.instance|get_class form.instance.pk %}"
|
||||
class="btn btn-danger"><i class="fas fa-trash-alt"></i> {% trans 'Delete' %}</a>
|
||||
{% if view_url %}
|
||||
<a href="{{ view_url }}" class="btn btn-info"><i class="far fa-eye"></i> {% trans 'View' %}</a>
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
<h3>{% trans 'New' %} {{ title }} </h3>
|
||||
|
||||
{% if form.Meta.model|get_class == 'Storage' %}
|
||||
{% if form.Meta.model|get_class_name == 'Storage' %}
|
||||
{% include 'include/storage_backend_warning.html' %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% block content %}
|
||||
|
||||
<h3>
|
||||
{% trans 'Meal-Plan' %} <a href="{% url 'new_plan' %}"><i class="fas fa-plus-circle"></i></a>
|
||||
{% trans 'Meal-Plan' %} <a href="{% url 'new_meal_plan' %}"><i class="fas fa-plus-circle"></i></a>
|
||||
</h3>
|
||||
|
||||
<div class="row">
|
||||
@ -55,7 +55,7 @@
|
||||
{% for day_key, days_value in plan_value.days.items %}
|
||||
<td>
|
||||
{% for mp in days_value %}
|
||||
<a href="{% url 'edit_plan' mp.pk %}"><i class="fas fa-edit"></i></a>
|
||||
<a href="{% url 'edit_meal_plan' mp.pk %}"><i class="fas fa-edit"></i></a>
|
||||
<a href="{% url 'view_recipe' mp.recipe.id %}">{{ mp.recipe.name }}</a><br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
|
@ -58,7 +58,7 @@
|
||||
<a class="btn btn-warning" href="{% url 'view_shopping' %}?r={{ recipe.pk }}"><i
|
||||
class="fas fa-shopping-cart"></i></a>
|
||||
{% endif %}
|
||||
<a class="btn btn-info" href="{% url 'new_plan' %}?recipe={{ recipe.pk }}"><i
|
||||
<a class="btn btn-info" href="{% url 'new_meal_plan' %}?recipe={{ recipe.pk }}"><i
|
||||
class="fas fa-calendar"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,17 +2,29 @@ from django import template
|
||||
import markdown as md
|
||||
import bleach
|
||||
from bleach_whitelist import markdown_tags, markdown_attrs, all_styles, print_attrs
|
||||
from django.urls import reverse
|
||||
|
||||
from cookbook.helper.mdx_attributes import MarkdownFormatExtension
|
||||
from cookbook.models import get_model_name
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter(name='get_class')
|
||||
def get_class(value):
|
||||
@register.filter()
|
||||
def get_class_name(value):
|
||||
return value.__class__.__name__
|
||||
|
||||
|
||||
@register.filter()
|
||||
def get_class(value):
|
||||
return value.__class__
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def delete_url(model, pk):
|
||||
return reverse(f'delete_{get_model_name(model)}', args=[pk])
|
||||
|
||||
|
||||
@register.filter()
|
||||
def markdown(value):
|
||||
tags = markdown_tags + ['pre', 'table', 'td', 'tr', 'th', 'tbody', 'style', 'thead']
|
||||
|
@ -1,3 +1,5 @@
|
||||
from pydoc import locate
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from .views import *
|
||||
@ -13,46 +15,16 @@ urlpatterns = [
|
||||
|
||||
path('view/recipe/<int:pk>', views.recipe_view, name='view_recipe'),
|
||||
|
||||
path('new/recipe/', new.RecipeCreate.as_view(), name='new_recipe'),
|
||||
path('new/recipe_import/<int:import_id>/', new.create_new_external_recipe, name='new_recipe_import'),
|
||||
path('new/keyword/', new.KeywordCreate.as_view(), name='new_keyword'),
|
||||
path('new/storage/', new.StorageCreate.as_view(), name='new_storage'),
|
||||
path('new/book/', new.RecipeBookCreate.as_view(), name='new_book'),
|
||||
path('new/plan/', new.MealPlanCreate.as_view(), name='new_plan'),
|
||||
|
||||
path('list/keyword', lists.keyword, name='list_keyword'),
|
||||
path('list/import_log', lists.sync_log, name='list_import_log'),
|
||||
path('list/import', lists.recipe_import, name='list_import'),
|
||||
path('list/storage', lists.storage, name='list_storage'),
|
||||
|
||||
path('edit/recipe/<int:pk>/', edit.switch_recipe, name='edit_recipe'),
|
||||
path('edit/recipe/internal/<int:pk>/', edit.internal_recipe_update, name='edit_internal_recipe'),
|
||||
# for internal use only
|
||||
path('edit/recipe/external/<int:pk>/', edit.RecipeUpdate.as_view(), name='edit_external_recipe'),
|
||||
# for internal use only
|
||||
path('edit/recipe/convert/<int:pk>/', edit.convert_recipe, name='edit_convert_recipe'), # for internal use only
|
||||
|
||||
path('edit/keyword/<int:pk>/', edit.KeywordUpdate.as_view(), name='edit_keyword'),
|
||||
path('edit/sync/<int:pk>/', edit.SyncUpdate.as_view(), name='edit_sync'),
|
||||
path('edit/import/<int:pk>/', edit.ImportUpdate.as_view(), name='edit_import'),
|
||||
path('edit/storage/<int:pk>/', edit.edit_storage, name='edit_storage'),
|
||||
path('edit/comment/<int:pk>/', edit.CommentUpdate.as_view(), name='edit_comment'),
|
||||
path('edit/recipe-book/<int:pk>/', edit.RecipeBookUpdate.as_view(), name='edit_recipe_book'),
|
||||
path('edit/plan/<int:pk>/', edit.MealPlanUpdate.as_view(), name='edit_plan'),
|
||||
path('edit/ingredient/', edit.edit_ingredients, name='edit_ingredient'),
|
||||
|
||||
path('redirect/delete/<slug:name>/<int:pk>/', delete.delete_redirect, name='redirect_delete'),
|
||||
|
||||
path('delete/recipe/<int:pk>/', delete.RecipeDelete.as_view(), name='delete_recipe'),
|
||||
path('delete/recipe-source/<int:pk>/', delete.RecipeSourceDelete.as_view(), name='delete_recipe_source'),
|
||||
path('delete/keyword/<int:pk>/', delete.KeywordDelete.as_view(), name='delete_keyword'),
|
||||
path('delete/sync/<int:pk>/', delete.MonitorDelete.as_view(), name='delete_sync'),
|
||||
path('delete/import/<int:pk>/', delete.ImportDelete.as_view(), name='delete_import'),
|
||||
path('delete/storage/<int:pk>/', delete.StorageDelete.as_view(), name='delete_storage'),
|
||||
path('delete/comment/<int:pk>/', delete.CommentDelete.as_view(), name='delete_comment'),
|
||||
path('delete/recipe-book/<int:pk>/', delete.RecipeBookDelete.as_view(), name='delete_recipe_book'),
|
||||
path('delete/recipe-book-entry/<int:pk>/', delete.RecipeBookEntryDelete.as_view(), name='delete_recipe_book_entry'),
|
||||
path('delete/plan/<int:pk>/', delete.MealPlanDelete.as_view(), name='delete_plan'),
|
||||
|
||||
path('data/sync', data.sync, name='data_sync'), # TODO move to generic "new" view
|
||||
path('data/batch/edit', data.batch_edit, name='data_batch_edit'),
|
||||
@ -69,3 +41,21 @@ urlpatterns = [
|
||||
path('dal/ingredient/', dal.IngredientsAutocomplete.as_view(), name='dal_ingredient'),
|
||||
path('dal/unit/', dal.UnitAutocomplete.as_view(), name='dal_unit'),
|
||||
]
|
||||
|
||||
generic_models = (Recipe, RecipeImport, Storage, RecipeBook, MealPlan, SyncLog, Sync, Comment, RecipeBookEntry, Keyword)
|
||||
|
||||
for m in generic_models:
|
||||
py_name = get_model_name(m)
|
||||
url_name = py_name.replace('_', '-')
|
||||
|
||||
if c := locate(f'cookbook.views.new.{m.__name__}Create'):
|
||||
urlpatterns.append(path(f'new/{url_name}/', c.as_view(), name=f'new_{py_name}'))
|
||||
|
||||
if c := locate(f'cookbook.views.edit.{m.__name__}Update'):
|
||||
urlpatterns.append(path(f'edit/{url_name}/<int:pk>/', c.as_view(), name=f'edit_{py_name}'))
|
||||
|
||||
if c := getattr(lists, py_name, None):
|
||||
urlpatterns.append(path(f'list/{url_name}/', c, name=f'list_{py_name}'))
|
||||
|
||||
if c := locate(f'cookbook.views.delete.{m.__name__}Delete'):
|
||||
urlpatterns.append(path(f'delete/{url_name}/<int:pk>/', c.as_view(), name=f'delete_{py_name}'))
|
||||
|
@ -1,5 +1,4 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import DeleteView
|
||||
@ -10,11 +9,6 @@ from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
|
||||
|
||||
# Generic Delete views
|
||||
def delete_redirect(request, name, pk):
|
||||
return redirect(('delete_' + name), pk)
|
||||
|
||||
|
||||
class RecipeDelete(LoginRequiredMixin, DeleteView):
|
||||
template_name = "generic/delete_template.html"
|
||||
model = Recipe
|
||||
@ -57,13 +51,13 @@ class ImportDelete(LoginRequiredMixin, DeleteView):
|
||||
return context
|
||||
|
||||
|
||||
class MonitorDelete(LoginRequiredMixin, DeleteView):
|
||||
class SyncDelete(LoginRequiredMixin, DeleteView):
|
||||
template_name = "generic/delete_template.html"
|
||||
model = Sync
|
||||
success_url = reverse_lazy('data_sync')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MonitorDelete, self).get_context_data(**kwargs)
|
||||
context = super(SyncDelete, self).get_context_data(**kwargs)
|
||||
context['title'] = _("Monitor")
|
||||
return context
|
||||
|
||||
|
@ -192,7 +192,7 @@ def edit_storage(request, pk):
|
||||
form = StorageForm(instance=pseudo_instance)
|
||||
|
||||
return render(request, 'generic/edit_template.html',
|
||||
{'form': form, 'view_url': reverse('view_recipe', args=[pk])})
|
||||
{'form': form})
|
||||
|
||||
|
||||
class CommentUpdate(LoginRequiredMixin, UpdateView):
|
||||
@ -342,4 +342,3 @@ def edit_ingredients(request):
|
||||
ingredients_form = IngredientMergeForm()
|
||||
|
||||
return render(request, 'forms/ingredients.html', {'units_form': units_form, 'ingredients_form': ingredients_form})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user