mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-10 00:28:22 -05:00
created CustomFilter model and api
This commit is contained in:
36
cookbook/migrations/0168_auto_20220121_1427.py
Normal file
36
cookbook/migrations/0168_auto_20220121_1427.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# Generated by Django 3.2.11 on 2022-01-21 20:27
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import cookbook.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0167_userpreference_left_handed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomFilter',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128)),
|
||||
('type', models.CharField(choices=[('RECIPE', 'Recipe'), ('FOOD', 'Food'), ('KEYWORD', 'Keyword')], default=('RECIPE', 'Recipe'), max_length=128)),
|
||||
('search', models.TextField()),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('shared', models.ManyToManyField(blank=True, related_name='f_shared_with', to=settings.AUTH_USER_MODEL)),
|
||||
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
|
||||
],
|
||||
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='customfilter',
|
||||
constraint=models.UniqueConstraint(fields=('space', 'name'), name='cf_unique_name_per_space'),
|
||||
),
|
||||
]
|
||||
@@ -1100,3 +1100,34 @@ class Automation(ExportModelOperationsMixin('automations'), models.Model, Permis
|
||||
|
||||
objects = ScopedManager(space='space')
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class CustomFilter(models.Model, PermissionModelMixin):
|
||||
RECIPE = 'RECIPE'
|
||||
FOOD = 'FOOD'
|
||||
KEYWORD = 'KEYWORD'
|
||||
|
||||
MODELS = (
|
||||
(RECIPE, _('Recipe')),
|
||||
(FOOD, _('Food')),
|
||||
(KEYWORD, _('Keyword')),
|
||||
)
|
||||
|
||||
name = models.CharField(max_length=128, null=False, blank=False)
|
||||
type = models.CharField(max_length=128, choices=(MODELS), default=MODELS[0])
|
||||
# could use JSONField, but requires installing extension on SQLite, don't need to search the objects, so seems unecessary
|
||||
search = models.TextField(blank=False, null=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
shared = models.ManyToManyField(User, blank=True, related_name='f_shared_with')
|
||||
|
||||
objects = ScopedManager(space='space')
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(fields=['space', 'name'], name='cf_unique_name_per_space')
|
||||
]
|
||||
|
||||
@@ -14,7 +14,7 @@ from rest_framework.fields import empty
|
||||
|
||||
from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
||||
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Food,
|
||||
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter, Food,
|
||||
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
|
||||
NutritionInformation, Recipe, RecipeBook, RecipeBookEntry,
|
||||
RecipeImport, ShareLink, ShoppingList, ShoppingListEntry,
|
||||
@@ -976,3 +976,16 @@ class FoodShoppingUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Recipe
|
||||
fields = ['id', 'amount', 'unit', 'delete', ]
|
||||
|
||||
|
||||
class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
shared = UserNameSerializer(many=True, required=False)
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
class Meta:
|
||||
model = CustomFilter
|
||||
fields = ('id', 'name', 'search', 'shared', 'created_by')
|
||||
read_only_fields = ('created_by',)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -9,15 +9,17 @@ from cookbook.helper import dal
|
||||
from recipes.settings import DEBUG
|
||||
from recipes.version import VERSION_NUMBER
|
||||
|
||||
from .models import (Automation, Comment, Food, InviteLink, Keyword, MealPlan, Recipe, RecipeBook,
|
||||
RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage, Supermarket,
|
||||
SupermarketCategory, Sync, SyncLog, Unit, UserFile, get_model_name)
|
||||
from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keyword, MealPlan, Recipe,
|
||||
RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Step, Storage,
|
||||
Supermarket, SupermarketCategory, Sync, SyncLog, Unit, UserFile,
|
||||
get_model_name)
|
||||
from .views import api, data, delete, edit, import_export, lists, new, telegram, views
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'automation', api.AutomationViewSet)
|
||||
router.register(r'bookmarklet-import', api.BookmarkletImportViewSet)
|
||||
router.register(r'cook-log', api.CookLogViewSet)
|
||||
router.register(r'custom-filter', api.CustomFilterViewSet)
|
||||
router.register(r'food', api.FoodViewSet)
|
||||
router.register(r'food-inherit-field', api.FoodInheritFieldViewSet)
|
||||
router.register(r'import-log', api.ImportLogViewSet)
|
||||
@@ -178,7 +180,7 @@ for m in generic_models:
|
||||
)
|
||||
)
|
||||
|
||||
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step]
|
||||
vue_models = [Food, Keyword, Unit, Supermarket, SupermarketCategory, Automation, UserFile, Step, CustomFilter]
|
||||
for m in vue_models:
|
||||
py_name = get_model_name(m)
|
||||
url_name = py_name.replace('_', '-')
|
||||
|
||||
@@ -42,18 +42,19 @@ from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
|
||||
from cookbook.helper.recipe_url_import import get_from_scraper
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
|
||||
from cookbook.models import (Automation, BookmarkletImport, CookLog, Food, FoodInheritField,
|
||||
ImportLog, Ingredient, Keyword, MealPlan, MealType, Recipe, RecipeBook,
|
||||
RecipeBookEntry, ShareLink, ShoppingList, ShoppingListEntry,
|
||||
ShoppingListRecipe, Step, Storage, Supermarket, SupermarketCategory,
|
||||
SupermarketCategoryRelation, Sync, SyncLog, Unit, UserFile,
|
||||
UserPreference, ViewLog)
|
||||
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, Food,
|
||||
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
|
||||
Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||
ShoppingListEntry, ShoppingListRecipe, Step, Storage, Supermarket,
|
||||
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit,
|
||||
UserFile, UserPreference, ViewLog)
|
||||
from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.local import Local
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
|
||||
from cookbook.serializer import (AutomationSerializer, BookmarkletImportSerializer,
|
||||
CookLogSerializer, FoodInheritFieldSerializer, FoodSerializer,
|
||||
CookLogSerializer, CustomFilterSerializer,
|
||||
FoodInheritFieldSerializer, FoodSerializer,
|
||||
FoodShoppingUpdateSerializer, ImportLogSerializer,
|
||||
IngredientSerializer, KeywordSerializer, MealPlanSerializer,
|
||||
MealTypeSerializer, RecipeBookEntrySerializer,
|
||||
@@ -900,7 +901,19 @@ class AutomationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
class CustomFilterViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = CustomFilter.objects
|
||||
serializer_class = CustomFilterSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter(
|
||||
space=self.request.space).distinct()
|
||||
return super().get_queryset()
|
||||
|
||||
# -------------- non django rest api views --------------------
|
||||
|
||||
|
||||
def get_recipe_provider(recipe):
|
||||
if recipe.storage.method == Storage.DROPBOX:
|
||||
return Dropbox
|
||||
|
||||
@@ -185,6 +185,22 @@ def automation(request):
|
||||
)
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def custom_filter(request):
|
||||
# recipe-param is the name of the parameters used when filtering recipes by this attribute
|
||||
# model-name is the models.js name of the model, probably ALL-CAPS
|
||||
return render(
|
||||
request,
|
||||
'generic/model_template.html',
|
||||
{
|
||||
"title": _("Custom Filters"),
|
||||
"config": {
|
||||
'model': "CUSTOM_FILTER", # *REQUIRED* name of the model in models.js
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def user_file(request):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user