NbaRo
NbaRo

Reputation: 83

Django how a user can add a new attribute to a model from template

I have the following model :

models.py :

class Product(models.Model):
name = models.CharField(blank=False, max_length=255)
description = models.TextField()


class Ingredients(models.Model):
    ingredients = models.ForeignKey(Product, related_name='ingredients', on_delete=models.CASCADE, null=True)
    salt = models.IntegerField(default=0)
    pepper = models.IntegerField(default=0)

views.py :

def productdetails(request, product_pk):
product = get_object_or_404(Product, pk=product_pk)
ingredients = get_object_or_404(Ingredients, ingredients_id=product_pk)
salt = ingredients.salt
pepper = ingredients.pepper
if request.method == 'POST':
    form = IngredientsForm(request.POST)
    newvalue = form.save(commit=False)
    newvalue.user = request.user
    newvalue.save()
    return render(request, 'xxx.html', {'product': product, 'form': IngredientsForm, 'salt': salt, 'pepper': pepper})
return render(request, 'xxx.html', {'product': product, 'iform': IngredientsForm, 'salt': salt, 'pepper': pepper})

def updateproduct(request, product_pk):
    ingredients = get_object_or_404(Ingredients, ingredients_id=product_pk)
    form = IngredientsForm(request.POST or None, instance = ingredients)
    salt = ingredients.salt
    pepper = ingredients.pepper
    if form.is_valid():
        form.save()
        products = Product.objects.filter()
        return render(request, 'xxx.html', {'products': products})
    return render(request, 'xxx.html', {'form': form, 'salt': salt, 'pepper': pepper, 'product_pk': product_pk})

def createingredients(request, product_pk):
    if request.method == 'POST':
        ingredients = get_object_or_404(Ingredients, ingredients_id=product_pk)    
        form = IngredientsForm(request.POST or None, instance=ingredients
        salt = ingredients.salt
        pepper = ingredients.pepper
        # here should be the code
        return render(request, 'xxx.html', {'ingredients': ingredients, 'product_pk': product_pk})

In template:

  <div class="container">
<strong>Ingredients:</strong>
<b>Salt: </b>{{ salt }} g <br>
<b>Pepper: </b>{{ pepper }} g <br>
<br>

  Update ingredients:
  {% if error %}
  <div class="alert alert-danger" role="alert">
      {{ error }}
  </div>
  {% endif %}
<form method="POST">
    {% csrf_token %}

    {{ form.as_p }}

    <input type="submit" value="Update">
</form>

<br>
Add ingredient:
<form action="{% url 'createingredients' product_pk %}" method="POST">
  {% csrf_token %}
  <br />
  <p>Name: <input type="text" name="ingredientname" /> Value: <input type="number" name="ingredientvalue" /> <input type="submit" value="Add"></p>
  <br />

</form>

What I try to achieve is that in the template the user should be able to add, delete, update and view Ingredients as he wish. For example, user can add the sugar ingredient of that product ( which is not defined in the ingredients models ) with the value of 150 and after that to delete the salt ingredient. In this case the template will need to list only sugar and pepper ( as salt was deleted by user ) ingredients of that product and allow user to always change values or add/delete more ingredients of that product from the product detail page. The user should be allowed to add as many ingredients as he wants, no matter if those ingredients are not in the ingredients models. Appreciate any help.

Upvotes: 0

Views: 457

Answers (1)

tstoev
tstoev

Reputation: 1435

What you want requires adding new columns in the ingredients table. Theoretically you can achieve that, with some scripting and custom management commands and cron jobs, but it will require you to build an entire sub-system that does it. Additionally allowing the user direct access to the database structure is not a practice you should consider in production ever. What you need is to alter your database design-replace the definition of the ingredients record with a type/name, value, unit triplet, and instead of adding column add records.

class Ingredients(models.Model):
    class TYPE:
        SALT   = 0
        PEPPER = 1
        #add more here
   
     class UNIT:
        GRAM = 0
        KILOGRAM = 1
        LITER    = 2
        POUND    = 3
        #add more here
        
        # an optional unit conversion 
        # call using Ingredients.UNIT.convert(unit1,unit2,quantity)
        @staticmethod
        def convert(from, to, quantity):
           factor = 1
           #calculate conversion factor here
           ....

           return quantity * factor        

    ingredients = models.ForeignKey(Product, related_name = 'ingredients',
                                             on_delete    = models.CASCADE, null=True)
    #an Ingredients.TYPE member. For example Ingredients.TYPE.SALT
    type     = models.IntegerField(default=0)
    #an Ingredients.UNIT memeber. For example Ingrediens.UNIT.GRAM
    unit     = models.IntegerField(default=0)

    quantity = models.IntegerField(default=0)
    

Upvotes: 1

Related Questions