Reputation: 1183
I have a list of menus--with items listed on the menu.
models.py:
class Menu(models.Model):
season = models.CharField(max_length=20)
items = models.ManyToManyField('Item', related_name='items')
created_date = models.DateTimeField(default=timezone.now)
expiration_date = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.season
class Item(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
chef = models.ForeignKey('auth.User')
created_date = models.DateTimeField(
default=timezone.now)
standard = models.BooleanField(default=False)
ingredients = models.ManyToManyField(
'Ingredient', related_name='ingredients'
)
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
For some reason--in the admin--i can edit the menu and it will save the items properly--but if i do so in the edit view for the menu it does not save the items (it does however save the season and expiration_date). That's why i thought maybe it was the ManyToMany relationship? Any ideas?
views.py:
def edit_menu(request, pk):
menu = get_object_or_404(Menu, pk=pk)
items = Item.objects.all()
admin = User.objects.get(username="admin")
if request.method == "POST":
ingredient = Ingredient(name="bug")
ingredient.save()
items = []
for i in request.POST.getlist('items'):
item = Item(name=i, chef=admin, description = "your description here", standard=False)
item.save()
items.append(item)
item.ingredients.add(ingredient)
if not Menu.objects.filter(pk=pk).exists():
menu=Menu(season=request.POST.get('season', ''),
expiration_date=datetime.strptime(request.POST.get('expiration_date', ''), '%m/%d/%Y'))
else:
menu=Menu.objects.get(pk=pk)
menu.items.delete()
menu.save()
for item in items:
menu.items.add(item)
return redirect('menu_detail', pk=menu.pk)
return render(request, 'menu/change_menu.html', {
'menu': menu,
'items': items,
})
and menu detail page,
template
{% extends "layout.html" %}
{% block content %}
<div class="content container">
<div class="row">
<div class="col-md-8">
<div class="post">
<h1>
{% if user.is_authenticated %}
<a class="btn btn-default" href="{% url 'menu_edit' pk=menu.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
{% endif %}
{{ menu.season }}
</h1>
<h2>On the menu this season:</h2>
<ul>
{% for item in menu.items.all %}
<li><a href="{% url 'item_detail' pk=item.pk %}">{{ item }}</a></li>
{% endfor %}
</ul>
{% if menu.expiration_date %}
<div class="date">
Menu expires on {{ menu.expiration_date|date:"F j, Y" }}
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}
UPDATE --changed edit view to this... now getting many to many error
def edit_menu(request, pk):
menu = get_object_or_404(Menu, pk=pk)
items = Item.objects.all()
admin = User.objects.get(username="admin")
if request.method == "POST":
ingredient = Ingredient(name="bug")
ingredient.save()
item = Item(name=request.POST.get('items', ''), chef=admin, description = "your description here", standard=False)
item.save()
item.ingredients.add(ingredient)
menu = Menu(season=request.POST.get('season', ''),
expiration_date=datetime.strptime(request.POST.get('expiration_date', ''), '%m/%d/%Y'))
menu.save()
menu.items.add(item)
return redirect('menu_detail', pk=menu.pk)
return render(request, 'menu/change_menu.html', {
'menu': menu,
'items': items,
})
UPDATE --adding change_menu template below
{% extends "layout.html" %}
{% block content %}
<div class="content container">
<div class="row">
<div class="col-md-8">
<h1>Change menu</h1>
<form action="" method="POST">{% csrf_token %}
<label for="season">Season:</label>
<input type="text" name="season" value="{{ menu.season }}">
<br />
<label for="items">Items:</label>
<select multiple>
{% for item in items %}
<option value="{{ item }}">{{ item}}</option>
{% endfor %}
</select>
<br />
<label for="expiration_date">Expiration Date:</label>
<input type="text" name="expiration_date" value="{{ menu.expiration_date|date:"m/d/Y" }}">
<br />
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
adding new_menu template below
{% extends "layout.html" %}
{% block content %}
<div class="content container">
<div class="row">
<div class="col-md-8">
<h1>Create New Menu</h1>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="button" value="Save">
</form>
</div>
</div>
</div>
{% endblock %}
Upvotes: 2
Views: 3253
Reputation: 5151
First create and save your ManyToMany
objects and then add them AFTER they have already been saved
ingredient = Ingredient(add parameters here)
ingredient.save()
# put items in a list so you can add them to menu later
items = []
# make new items from option box in template
for i in request.POST.getlist('items'):
item = Item(name=i, chef=admin, description = "your description here", standard=False)
item.save()
items.append(item)
item.ingredients.add(ingredient)
if not Menu.objects.filter(pk=pk).exists():
menu=Menu(season=request.POST.get('season', ''), expiration_date=datetime.strptime(request.POST.get('expiration_date', ''), '%m/%d/%Y'))
else:
menu=Menu.objects.get(pk=pk)
# we will be replacing the old menu items
menu.items.clear()
menu.save()
for item in items:
menu.items.add(item)
Upvotes: 1
Reputation: 9235
You need to edit your views like this,
def edit_menu(request, pk):
menu = get_object_or_404(Menu, pk=pk)
items = Item.objects.all()
if request.method == "POST":
item_name = request.POST.get('items')
season = request.POST.get('season')
exp_date = datetime.strptime(request.POST.get('expiration_date'), '%m/%d/%Y')
try:
item = Item.objects.get(name=item_name)
except:
item = Item.objects.create(name=item_name, description = "description_here", ingredients="ingredients_here", standard=False)
menu = Menu.objects.create(season=season, expiration_date=exp_date)
menu.items.add(item)
menu.save()
return redirect('menu_detail', pk=menu.pk)
return render(request, 'menu/change_menu.html', {
'menu': menu,
'items': items,
})
You can't add a many to many relation, without commiting the model to the database. First you have to save the menu object, then you need to add item
to the items
of menu.
Upvotes: 1