0

I want to replicate the admin functionality shown in the screenshot below on the client side. This is app is meant to cost a recipe based on the ingredients and quantity.

enter image description here

Find below some snippets of my code

admin.py

class RecipeIngredientInline(admin.TabularInline):
    model = RecipeIngredient
    extra=0

class RecipeAdmin(admin.ModelAdmin):
    inlines = [RecipeIngredientInline]

admin.site.register(Recipe, RecipeAdmin)

models.py

class Ingredient(models.Model):
    ingredient_name = models.CharField(max_length=255)
    unit_of_measure = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=20, decimal_places=2)
    units_size_in_package = models.DecimalField(max_digits=20, decimal_places=2)
    cost_per_unit = models.DecimalField(max_digits=20, decimal_places=2)
    supplier = models.CharField(max_length=255, null=True, blank=True)
    create_date = models.DateTimeField(auto_now_add=True, blank=True)
    edit_date = models.DateTimeField(auto_now=True, blank=True)

class Recipe(models.Model):  
    recipe_name = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)
    photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True, null=True)
    product_category = models.ForeignKey(ProductCategory, on_delete=models.SET_NULL, blank=True, null=True)
    ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient')
    is_vatable = models.BooleanField(default=False)
    VAT_percentage = models.PositiveIntegerField(blank=True, null=True)
    VAT = models.FloatField(blank=True, null=True)
    create_date = models.DateTimeField(auto_now_add=True, blank=True)
    edit_date = models.DateTimeField(auto_now=True, blank=True)

class RecipeIngredient(models.Model):
    recipe = models.ForeignKey(Recipe, blank=True, null=True, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, blank=True, null=True, on_delete=models.CASCADE)
    quantity = models.DecimalField(max_digits=20, decimal_places=2)
    cost = models.FloatField(blank=True, null=True)
    create_date = models.DateTimeField(auto_now_add=True, blank=True)
    edit_date = models.DateTimeField(auto_now=True, blank=True)

forms.py

class RecipeForm(forms.ModelForm):
    product_category = forms.ModelChoiceField(queryset=ProductCategory.objects.all())

    class Meta:
        model = Recipe
        fields = ['recipe_name', 'description', 'photo', 'product_category', 'ingredients', 'is_vatable', 
                    'VAT_percentage' ]
        widgets = {
             'description': forms.Textarea(
                attrs={
                    'rows': 4,
                }
            ),
            'VAT_percentage': forms.NumberInput(
                attrs={
                    'class': 'form-control',
                }
            ),
        }
     
        )

class RecipeIngredientForm(forms.ModelForm):
    ingredient = forms.ModelChoiceField(
            queryset=Ingredient.objects.all(),
            widget=forms.Select(attrs={'class': 'form-control'})
        )
    cost = forms.CharField(required = False)

    class Meta:
        Model = RecipeIngredient
        fields=['ingredient', 'quantity', 'cost' ]
        widgets = {
             'quantity': forms.NumberInput(
                attrs={
                    'class': 'form-control',
                }
            ),
            'cost': forms.NumberInput(
                attrs={
                    'class': 'form-control',
                }
            ),
        }

RecipeIngredientFormset = inlineformset_factory(Recipe,
    Recipe.ingredients.through,
    form=RecipeIngredientForm,
    extra=2, 
    can_delete=True
)

I am unable to add records to the parent and through table (Recipe and RecipeIngredient) so I suppose my view is not working fine. I have tried adapting the view in this question but it didn't work Add row dynamically in django formset

My current idea shown below is also not working. I am stuck and need help on where I am going wrong with the view.

views.py

from .models import Recipe, RecipeIngredient
from .forms import RecipeForm, RecipeIngredientFormset

def recipe_create_view(request):
    form = RecipeForm(request.POST or None, request.FILES or None)
    formset = RecipeIngredientFormset(request.POST or None)
    if form.is_valid() and formset.is_valid():
        recipe = form.save(commit=False)
        recipe.save()
        for each_form in formset:
            recipe_ingredient = each_form.save(commit=False)
            if recipe_ingredient.recipe is None:
                recipe_ingredient.recipe = recipe
            recipe_ingredient.save()
        return redirect('/costing/recipes')
    context = {
        'form': form,
        'formset': formset,
    }
    return render(request, 'recipes/recipe_create.html', context)

1 Answers1

0
def recipe_create_view(request):
    form = RecipeForm(request.POST or None, request.FILES or None)
    if request.POST and form.is_valid():
        recipe = form.save(commit=False)
        formset = RecipeIngredientFormset(request.POST, instance=recipe)
        if formset.is_valid():
            recipe.save()
            formset.save()
            return redirect('/costing/')
    else:
        formset = RecipeIngredientFormset(request.POST or None, instance=Recipe())
    context = {
        'form': form, 
        'formset': formset
    }
    return render(request, 'recipes/recipe_create.html', context)