feat(dailyrecipe and week recipe): [A] 增加dailyrecipe 每日菜单,增加 weekrecipe 接口

[A] 增加dailyrecipe 每日菜单,增加 weekrecipe 接口

Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
Ching 2021-10-02 20:28:35 +08:00
parent b4fa5d9519
commit 1dd97b9e54
7 changed files with 298 additions and 9 deletions

View File

@ -0,0 +1,27 @@
# Generated by Django 3.2.6 on 2021-10-02 11:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('recipe', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='recipe',
name='recipe_type',
field=models.CharField(default='meat', max_length=32),
),
migrations.CreateModel(
name='DailyRecipe',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateField()),
('meal_type', models.CharField(default='supper', max_length=32)),
('recipes', models.ManyToManyField(to='recipe.Recipe')),
],
),
]

View File

@ -1,9 +1,101 @@
import random
from django.db import models from django.db import models
from django.utils.timezone import now
from utils import const
import utils
# Create your models here.
class Recipe(models.Model): class Recipe(models.Model):
name = models.CharField(max_length=128) name = models.CharField(max_length=128)
recipe_type = models.CharField(max_length=32) recipe_type = models.CharField(max_length=32,
default=const.RECIPE_TYPE_MEAT)
note = models.TextField(null=True) note = models.TextField(null=True)
rate = models.IntegerField(default=0) rate = models.IntegerField(default=0)
difficulty = models.IntegerField(default=0) difficulty = models.IntegerField(default=0)
def serialize(self, verbose=False):
data = {
'id': self.id,
'name': self.name,
'recipe_type': self.recipe_type,
}
if verbose:
data.update({
'difficulty': self.difficulty,
'rate': self.rate,
'note': self.note,
})
return data
class DailyRecipe(models.Model):
recipes = models.ManyToManyField(Recipe)
date = models.DateField()
meal_type = models.CharField(
max_length=32,
default=const.DAILY_RECIPE_MEAL_TYPE_SUPPER,)
def generate_recipe(self, prev_recipes=None, ignore_prev=False):
if not prev_recipes:
prev_recipes = []
if ignore_prev:
prev_recipes = []
recipes = []
retry = 5
# meat
for x in range(0,2):
while True:
recipe = Recipe.objects.filter(
recipe_type=const.RECIPE_TYPE_MEAT,
).order_by('?').first()
if recipe.id not in recipes and recipe.id not in prev_recipes:
recipes.append(recipe.id)
break
if retry <= 0:
retry = 5
break
# vegetable
for x in range(0, 1):
while True:
recipe = Recipe.objects.filter(
recipe_type=const.RECIPE_TYPE_VEGETABLE,
).order_by('?').first()
if recipe.id not in recipes and recipe.id not in prev_recipes:
recipes.append(recipe.id)
break
retry -= 1
if retry <= 0:
retry = 5
break
# soup
if random.randint(0,2):
recipe = Recipe.objects.filter(
recipe_type=const.RECIPE_TYPE_SOUP,
).order_by('?').first()
# if recipe not in recipes and recipe not in prev_recipes:
if recipe:
recipes.append(recipe.id)
self.recipes.set(Recipe.objects.filter(id__in=recipes))
def serialize(self):
data = {
const.RECIPE_TYPE_MEAT: [],
const.RECIPE_TYPE_VEGETABLE: [],
const.RECIPE_TYPE_SOUP: [],
}
for key_, value_ in data.items():
for recipe in self.recipes.filter(
recipe_type=key_).order_by('id'):
value_.append(recipe.serialize())
date = now()
date.replace(year=self.date.year, month=self.date.month, day=self.date.day,)
data['date'] = utils.timestamp_of(utils.day_start(date))
return data

View File

@ -8,3 +8,10 @@ class RecipeSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = recipe.models.Recipe model = recipe.models.Recipe
fields = '__all__' fields = '__all__'
class WeekRecipeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = recipe.models.DailyRecipe
fields = '__all__'

View File

@ -10,4 +10,5 @@ from recipe import views
urlpatterns = [ urlpatterns = [
url(r'^recipe/(?P<pk>\d+)$', views.RecipeAPI.as_view(), name='recipe-detail'), url(r'^recipe/(?P<pk>\d+)$', views.RecipeAPI.as_view(), name='recipe-detail'),
url(r'^recipe/$', views.RecipeListAPI.as_view()), url(r'^recipe/$', views.RecipeListAPI.as_view()),
url(r'^week-recipe/$', views.WeekRecipeListAPI.as_view()),
] ]

View File

@ -1,11 +1,7 @@
import datetime
from django.shortcuts import render from django.shortcuts import render
from django.utils.timezone import now, localtime
# Create your views here.
import django.views.generic
from django.http import JsonResponse
from django.urls import reverse
from rest_framework import authentication, permissions, status, viewsets from rest_framework import authentication, permissions, status, viewsets
import rest_framework.generics import rest_framework.generics
from rest_framework.response import Response from rest_framework.response import Response
@ -34,3 +30,33 @@ class RecipeListAPI(rest_framework.generics.ListAPIView,
queryset = recipe.models.Recipe.objects.all() queryset = recipe.models.Recipe.objects.all()
serializer_class = recipe.serializers.RecipeSerializer serializer_class = recipe.serializers.RecipeSerializer
class WeekRecipeListAPI(rest_framework.generics.ListAPIView,
rest_framework.generics.CreateAPIView):
queryset = recipe.models.DailyRecipe.objects.all()
serializer_class = recipe.serializers.WeekRecipeSerializer
def post(self, request, *args, **kwargs):
# Monday == 0 ... Sunday == 6
today = localtime()
recipes = []
for x in range(0, 7-today.weekday()):
daily_recipe, __ = recipe.models.DailyRecipe.objects.get_or_create(
date=today + datetime.timedelta(days=1)
)
daily_recipe.generate_recipe()
recipes.append(daily_recipe.recipes.values_list('id', flat=True))
return Response({}, status=status.HTTP_201_CREATED, headers={})
def get(self, request, *args, **kwargs):
today = localtime()
week_start = (today - datetime.timedelta(days=today.weekday())).date()
week_end = week_start + datetime.timedelta(days=6)
daily_recipes = recipe.models.DailyRecipe.objects.filter(
date__gte=week_start,
date__lte=week_end,
).order_by('date')
data = []
for daily_recipe in daily_recipes:
data.append(daily_recipe.serialize())
return Response(data)

118
utils/__init__.py Normal file
View File

@ -0,0 +1,118 @@
# -*- coding: UTF-8 -*-
import calendar
from datetime import timedelta
from django.utils import timezone
def timestamp_of(d):
if hasattr(d, 'isoformat'):
return calendar.timegm(d.utctimetuple())
return None
def now():
return timezone.localtime(timezone.now())
def midnight():
return now().replace(hour=0, minute=0, second=0, microsecond=0)
def is_today(tme):
if day_of(tme) != day_of(midnight()):
return False
return True
def current_time_n(n):
return now() - timedelta(days=n)
def day_n(n):
"""Midnight of N days ago."""
return midnight() - timedelta(days=n)
def day_of(d):
"""Returns date part."""
return str(d.date())
def midnight_of(d):
"""
Args:
d : datetime object
Return:
Midnight of datetime.
"""
d = timezone.localtime(d)
return d.replace(hour=0, minute=0, second=0, microsecond=0)
def day_start(date):
""" 返回 date 这天的开始时间
Args:
date: `Datetime` 对象
Returns:
返回 date 这天的开始时间0 `Datetime` 对象
"""
return timezone.localtime(date).replace(hour=0, minute=0, second=0,
microsecond=0)
def week_start(date):
""" 返回 date 这天所在周的开始时间
Args:
date: `Datetime` 对象
Returns:
返回 date 这天所在周开始时间周一`Datetime` 对象
"""
return timezone.localtime(date) + dateutil.relativedelta.relativedelta(
weekday=dateutil.relativedelta.MO(-1), hour=0, minute=0, second=0,
microsecond=0)
def month_start(d):
""" 返回 date 这天所在月的开始时间
Args:
date: `Datetime` 对象
Returns:
返回 date 这天所在月的开始时间1`Datetime` 对象
"""
return timezone.localtime(d) + dateutil.relativedelta.relativedelta(
day=1, hour=0, minute=0, second=0, microsecond=0)
def month_end(d):
"""返回 date 这天所在月的结束时间,即最后一天的 23:59:59
Args:
data: `Datetime` 对象
Returns:
返回 date 这天所在月的最后一天的 23:59:59 的时间
"""
start = month_start(d)
month_days = calendar.monthrange(start.year, start.month)[1]
return start + timedelta(days=month_days, seconds=-1)
def year_start(d):
""" 返回 date 这天所在年的开始时间
Args:
date: `Datetime` 对象
Returns:
返回 date 这天所在年的开始时间1 1`Datetime` 对象
"""
return timezone.localtime(d) + dateutil.relativedelta.relativedelta(
month=1, day=1, hour=0, minute=0, second=0, microsecond=0)

18
utils/const.py Normal file
View File

@ -0,0 +1,18 @@
DAILY_RECIPE_MEAL_TYPE_BREAKFAST = 'breakfast'
DAILY_RECIPE_MEAL_TYPE_LUNCH = 'lunch'
DAILY_RECIPE_MEAL_TYPE_SUPPER = 'supper'
DAILY_RECIPE_MEAL_TYPE_CHOICE = [
DAILY_RECIPE_MEAL_TYPE_BREAKFAST,
DAILY_RECIPE_MEAL_TYPE_LUNCH,
DAILY_RECIPE_MEAL_TYPE_SUPPER,
]
RECIPE_TYPE_MEAT = 'meat'
RECIPE_TYPE_VEGETABLE = 'vegetable'
RECIPE_TYPE_SOUP = 'soup'
RECIPE_TYPE_CHOICE = [
RECIPE_TYPE_MEAT,
RECIPE_TYPE_VEGETABLE,
RECIPE_TYPE_SOUP,
]