image upload working

This commit is contained in:
vabene1111
2020-06-29 15:39:58 +02:00
parent d613da7faf
commit 27963fcaa6
5 changed files with 93 additions and 32 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.7 on 2020-06-29 13:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0066_auto_20200626_1455'),
]
operations = [
migrations.AlterField(
model_name='ingredient',
name='note',
field=models.CharField(blank=True, max_length=256, null=True),
),
]

View File

@ -149,7 +149,7 @@ class Ingredient(models.Model):
food = models.ForeignKey(Food, on_delete=models.PROTECT) food = models.ForeignKey(Food, on_delete=models.PROTECT)
unit = models.ForeignKey(Unit, on_delete=models.PROTECT) unit = models.ForeignKey(Unit, on_delete=models.PROTECT)
amount = models.DecimalField(default=0, decimal_places=16, max_digits=32) amount = models.DecimalField(default=0, decimal_places=16, max_digits=32)
note = models.CharField(max_length=64, null=True, blank=True) note = models.CharField(max_length=256, null=True, blank=True)
order = models.IntegerField(default=0) order = models.IntegerField(default=0)
def __str__(self): def __str__(self):

View File

@ -99,8 +99,14 @@ class RecipeSerializer(WritableNestedModelSerializer):
class Meta: class Meta:
model = Recipe model = Recipe
fields = '__all__' fields = ['name', 'image', 'keywords', 'steps', 'working_time', 'waiting_time', 'created_by', 'created_at', 'updated_at', 'internal']
validators = [] read_only_fields = ['image', 'created_by', 'created_at']
class RecipeImageSerializer(WritableNestedModelSerializer):
class Meta:
model = Recipe
fields = ['image', ]
class RecipeImportSerializer(serializers.ModelSerializer): class RecipeImportSerializer(serializers.ModelSerializer):

View File

@ -50,15 +50,17 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
Image Edit Placeholder <img src="{{ recipe.image.url }}" id="id_image" class="img img-fluid img-responsive"
style="max-height: 20vh">
<input type="file" @change="imageChanged">
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label for="id_name"> {% trans 'Preperation Time' %}</label> <label for="id_name"> {% trans 'Preperation Time' %}</label>
<input class="form-control" id="id_prep_time" v-model="recipe.working_time"> <input class="form-control" id="id_prep_time" v-model="recipe.working_time">
<br/>
<label for="id_name"> {% trans 'Waiting Time' %}</label> <label for="id_name"> {% trans 'Waiting Time' %}</label>
<input class="form-control" id="id_wait_time" v-model="recipe.waiting_time"> <input class="form-control" id="id_wait_time" v-model="recipe.waiting_time">
<br/>
<label for="id_name"> {% trans 'Keywords' %}</label> <label for="id_name"> {% trans 'Keywords' %}</label>
<multiselect <multiselect
v-model="recipe.keywords" v-model="recipe.keywords"
@ -67,7 +69,7 @@
:clear-on-select="true" :clear-on-select="true"
:hide-selected="true" :hide-selected="true"
:preserve-search="true" :preserve-search="true"
placeholder="{% trans 'Select one' %}" placeholder="{% trans 'Select Keywords' %}"
label="name" label="name"
track-by="id" track-by="id"
id="id_keywords" id="id_keywords"
@ -94,27 +96,6 @@
<div class="row"> <div class="row">
<div class="col-md-12" style="margin-top: 12px"> <div class="col-md-12" style="margin-top: 12px">
<!--<div class="row" style="text-align: center">
<div class="col-md-1 no-gutters">
<b><i class="fas fa-arrows-alt-v"></i></b>
</div>
<div class="col-md-2">
<b>{% trans 'Amount' %}</b>
</div>
<div class="col-md-3">
<b>{% trans 'Unit' %}</b>
</div>
<div class="col-md-3">
<b>{% trans 'Food' %}</b>
</div>
<div class="col-md-2">
<b>{% trans 'Note' %}</b>
</div>
<div class="col-md-1">
<i class="fa fa-trash"></i>
</div>
</div>-->
<draggable :list="step.ingredients" group="ingredients" <draggable :list="step.ingredients" group="ingredients"
:empty-insert-threshold="10" handle=".handle" @sort="sortStep(step)"> :empty-insert-threshold="10" handle=".handle" @sort="sortStep(step)">
<div class="col-md-12" v-for="ingredient, index in step.ingredients" :key="ingredient.id" <div class="col-md-12" v-for="ingredient, index in step.ingredients" :key="ingredient.id"
@ -206,6 +187,8 @@
<button type="button" @click="updateRecipe(true)" class="btn btn-success">{% trans 'Save & View' %}</button> <button type="button" @click="updateRecipe(true)" class="btn btn-success">{% trans 'Save & View' %}</button>
<button type="button" @click="updateRecipe(false)" class="btn btn-info">{% trans 'Save' %}</button> <button type="button" @click="updateRecipe(false)" class="btn btn-info">{% trans 'Save' %}</button>
<button type="button" @click="addStep()" class="btn btn-primary">{% trans 'Add Step' %}</button> <button type="button" @click="addStep()" class="btn btn-primary">{% trans 'Add Step' %}</button>
<a href="{% url 'view_recipe' recipe.pk %}" @click="addStep()"
class="btn btn-secondary">{% trans 'View Recipe' %}</a>
<br/> <br/>
<br/> <br/>
</div> </div>
@ -257,7 +240,8 @@
}) })
}, },
updateRecipe: function (view_after) { updateRecipe: function (view_after) {
this.$http.put("{% url 'api:recipe-detail' recipe.pk %}", this.recipe).then((response) => { this.$http.put("{% url 'api:recipe-detail' recipe.pk %}", this.recipe,
{}).then((response) => {
console.log(view_after) console.log(view_after)
console.log(response) console.log(response)
if (view_after) { if (view_after) {
@ -266,6 +250,28 @@
}).catch((err) => { }).catch((err) => {
console.log(err) console.log(err)
}) })
},
imageChanged: function (event) {
if (event.target.files && event.target.files[0]) {
let fd = new FormData()
fd.append('image', event.target.files[0])
this.$http.put("{% url 'api:recipe-detail' recipe.pk %}" + 'image/', fd,
{headers: {'Content-Type': 'multipart/form-data'}}).then((response) => {
console.log(response)
}).catch((err) => {
console.log(err)
})
let reader = new FileReader();
reader.onload = function (e) {
$('#id_image').attr('src', e.target.result);
}
reader.readAsDataURL(event.target.files[0]);
}
}, },
addStep: function () { //TODO see if default can be generated from options request addStep: function () { //TODO see if default can be generated from options request
this.recipe.steps.push( this.recipe.steps.push(
@ -290,7 +296,6 @@
if (confirm('{% trans 'Are you sure that you want to delete this ingredient?' %}')) { if (confirm('{% trans 'Are you sure that you want to delete this ingredient?' %}')) {
step.ingredients = step.ingredients.filter(item => item !== ingredient) step.ingredients = step.ingredients.filter(item => item !== ingredient)
} }
}, },
searchKeywords: function (query) { searchKeywords: function (query) {
this.keywords_loading = true this.keywords_loading = true

View File

@ -1,20 +1,25 @@
import io import io
import json import json
import re import re
import uuid
import requests import requests
from PIL import Image
from annoying.decorators import ajax_request from annoying.decorators import ajax_request
from annoying.functions import get_object_or_None from annoying.functions import get_object_or_None
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File
from django.db.models import Q from django.db.models import Q
from django.http import HttpResponse, FileResponse, JsonResponse from django.http import HttpResponse, FileResponse, JsonResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from icalendar import Calendar, Event from icalendar import Calendar, Event
from rest_framework import viewsets, permissions from rest_framework import viewsets, permissions, decorators
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, ListModelMixin from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, ListModelMixin
from rest_framework.parsers import JSONParser, FileUploadParser, MultiPartParser
from rest_framework.response import Response
from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser
from cookbook.helper.recipe_url_import import get_from_html from cookbook.helper.recipe_url_import import get_from_html
@ -22,7 +27,7 @@ from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType,
from cookbook.provider.dropbox import Dropbox from cookbook.provider.dropbox import Dropbox
from cookbook.provider.nextcloud import Nextcloud from cookbook.provider.nextcloud import Nextcloud
from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \ from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \
KeywordSerializer KeywordSerializer, RecipeImageSerializer
class UserNameViewSet(viewsets.ModelViewSet): class UserNameViewSet(viewsets.ModelViewSet):
@ -180,6 +185,33 @@ class RecipeViewSet(viewsets.ModelViewSet):
queryset = queryset[:int(limit)] queryset = queryset[:int(limit)]
return queryset return queryset
@decorators.action(
detail=True,
methods=['PUT'],
serializer_class=RecipeImageSerializer,
parser_classes=[MultiPartParser],
)
def image(self, request, pk):
obj = self.get_object()
serializer = self.serializer_class(obj, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
img = Image.open(obj.image)
basewidth = 720
wpercent = (basewidth / float(img.size[0]))
hsize = int((float(img.size[1]) * float(wpercent)))
img = img.resize((basewidth, hsize), Image.ANTIALIAS)
im_io = io.BytesIO()
img.save(im_io, 'PNG', quality=70)
obj.image = File(im_io, name=f'{uuid.uuid4()}_{obj.pk}.png')
obj.save()
return Response(serializer.data)
return Response(serializer.errors, 400)
class KeywordViewSet(viewsets.ModelViewSet): class KeywordViewSet(viewsets.ModelViewSet):
""" """