i would like to make a structure database for a restaurant menu without using mptt or django-tree. here is my models.py:
from django.db import models
class Menu(models.Model):
name = models.CharField(max_length=24, unique=True, verbose_name='menu name')
#slug = models.SlugField(max_length=24, unique=True, help_text='The slug is the URL friendly version of the menu name, so that this can be accessed at a URL like mysite.com/menus/dinner/.')
additional_text = models.CharField(max_length=128, null=True, blank=True, help_text='Any additional text that the menu might need, i.e. Served between 11:00am and 4:00pm.')
order = models.PositiveSmallIntegerField(default=0, help_text='The order of the menu determines where this menu appears alongside other menus.')
class Meta:
ordering = ['name', 'order']
class MenuCategory(models.Model):
menu = models.ForeignKey(Menu, on_delete=models.CASCADE,help_text='The menus that this category belongs to, i.e. \'Lunch\'.')
name = models.CharField(max_length=32, verbose_name='menu category name')
additional_text = models.CharField(max_length=128, null=True, blank=True, help_text='The additional text is any bit of related information to go along with a menu category, i.e. the \'Pasta\' category might have details that say \'All entrees come with salad and bread\'.')
order = models.IntegerField(default=0, help_text='The order is the order that this category should appear in when rendered on the templates.')
class Meta:
verbose_name='menu category'
verbose_name_plural='menu categories'
ordering = ['order', 'name']
def __unicode__(self):
return self.name
class MenuItem(models.Model):
CLASSIFICATION_CHOICES = (
('neither', 'Neither'),
('vegan', 'Vegan'),
('vegetarian', 'Vegetarian'),
)
name = models.CharField(max_length=48, help_text='Name of the item on the menu.')
description = models.CharField(max_length=128, null=True, blank=True, help_text='The description is a simple text description of the menu item.')
category = models.ManyToManyField(MenuCategory, verbose_name='menu category', help_text='Category is the menu category that this menu item belongs to, i.e. \'Appetizers\'.')
order = models.IntegerField(default=0, verbose_name='order', help_text='The order is to specify the order in which items show up on the menu.')
price = models.IntegerField(help_text='The price is the cost of the item.')
image = models.ImageField(upload_to='menu', null=True, blank=True, verbose_name='image', help_text='The image is an optional field that is associated with each menu item.')
class Meta:
verbose_name='menu item'
verbose_name_plural='menu items'
ordering = ['classification', 'order', 'name']
def __unicode__(self):
return self.name
views.py:
from .models import Menu,MenuCategory
from django.views.generic import ListView
class MenuView(ListView):
model= Menu
conext_object_name='name'
template_name = 'menu_list.html'
queryset = Menu.objects.all()
def get_context_data(self, **kwargs):
context = super(MenuView, self).get_context_data(**kwargs)
context['Menucategory'] = MenuCategory.objects.all()
context['Menus'] = self.queryset
return context
menu_list.html:
<div>
{%for item in Menu%}
<p>
{{item.menu}}
{{item.name}}
{{item.additiona_text}}
{{item.order}}
</p>
{%endfor%}
{%for item in MenuCategory%}
<p>
{{item.name}}
{{item.additiona_text}}
{{item.order}}
</p>
{%endfor%}
</div>
when i browse localhost page after executing runserver, it shows only
Django blog
Breakfast 1
Lunch 2
Dinner 3
but my desired output should be:
1)Breakfast
coffee
Items
1 2 3
Snacks Items 1 2 3
2)Lunch
Starter items 1 2 3
Main Courses Items 1 2 3
how can i get this structured table using plain bootstrap table row column where in every row column i will query the items with for loop? is their any other way? If there is alternative way, i am also interested....
I think your design is not good in the first place. If you want to display things in such a way, the logic would be the following:
you have menu categories (breakfast, lunch, dinner...),
you have menu items (coffee...) which belong to one or many menu categories,
you have menus which belong to one category
So, your data structure should be the following:
class MenuItem(models.Model):
# [...]
class MenuCategory(models.Model):
# [...]
name = CharField...
items = models.ManyToManyField(MenuItem)
class Menu(models.Model):
# [...]
menu_category = models.ForeignKey(MenuCategory)
Then, you could do what you want in your template (note: to name a queryset by its class name is a very bad practice. Just call it menus! That is what I'll do here) with a double for loop:
<div>
{% for menu in menus %}
<h3>
{{ menu.menu_category.name }}
</h3>
<p>
{%for item in menu.menu_category.items.all %}
{{ item.name }}
{% endfor %}
</p>
{% endfor %}
</div>
Once again, your initial design is not the most appropriate in my opinion.
Hope that helps!
Related
I'm building an ecommerce app and I'd like to make a section that shows some featured items by category. I'm using three sliders that display those items; Each slider is a featured category and each item in the slider is a featured item.
The problem is that I can't figure out how to assign the item to the proper slider. For example: I want to assign a JeansJacket to "Clothes and accesories" and display it. I tried this:
{% for cat in categories %}
<h1>{{ cat.cat_name }}</h1>
<!--(carousel code in between)-->
<div class="carousel-inner" role="listbox">
{% for item in featured_items %}
{% if item.Categoría in cat.cat_name %}
{{ item }}
{% endif %}
This is a simplified version of what I have, without the rest of the content. I just can't figure out how to iterate though the featured items and display them in the corresponding category.
Edit: This is in models.py:
class Categorías(models.Model):
cat_name = models.CharField(max_length=30)
Destacado = models.BooleanField()
class Meta:
ordering = ('cat_name',)
verbose_name = 'Categoría'
verbose_name_plural = 'Categorías'
def __str__(self):
return self.cat_name
class publicaciones(models.Model):
Título = models.CharField(max_length=30)
Descripción = models.TextField(max_length=200)
Precio = models.FloatField()
Fotos = models.ImageField()
Categoría = models.ForeignKey(Categorías, on_delete=models.CASCADE)
Promocionado = models.BooleanField()
class Meta:
verbose_name = 'Publicación'
verbose_name_plural = 'Publicaciones'
def __str__(self):
return self.Título
You can use prefetch_related and Prefetch with a custom query to get all related articles for each category.
categories = Categorías.objects.prefetch_related(Prefetch(
'publicaciones_set',
queryset=publicaciones.objects.filter(Promocionado=True),
to_attr='featured_items'
))
Now you can loop over each category and then loop over this prefetch. You don't need to create a separate featured_items queryset
for category in categories:
for featured_item in category.featured_items:
...
You can use apply this pattern to your template
I have such models
class Employee(models.Model):
"""Employee information."""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='employee', unique=True)
position = models.CharField("current position in a company", max_length=64, blank=True)
birth_date = models.DateField("date of birth", null=True)
skills = models.ManyToManyField(
Technology, through="Skill", verbose_name="skills", blank=True)
class Technology(models.Model):
"""Technologies."""
name = models.CharField('technology name', max_length=32, unique=True)
class Skill(models.Model):
"""Information about an employee's skills."""
LEVELS = (
('basic', 'Basic'),
('intermediate', 'Intermediate'),
('advanced', 'Advanced'),
('expert', 'Expert'),
)
employee = models.ForeignKey(
Employee, on_delete=models.CASCADE, related_name="employee_skills")
technology = models.ForeignKey(Technology, on_delete=models.CASCADE)
start_date = models.DateField(
verbose_name='Works with since:')
level = models.CharField("level", max_length=64, choices=LEVELS)
And I can't understand why my template code doesn't work
template.html
{{ user.employee.position }}
{{ user.employee.birth_date }}
{{ user.employee.summary }}
{% for i in user.employee.skills.all %}
{{ i.technology.name }}
{{ i.level }}
{% endfor %}
I can't see absolutely nothing. All models possible to see at adminpanel. And else then I using TemplateView such as
class AccountView(TemplateView):
template_name = "profile.html"
def get_context_data(self, **kwargs):
context = super(AccountView, self).get_context_data(**kwargs)
context['skills'] =
Skill.objects.filter(employee__user=self.request.user)
return context
then everything works fine.
There is something wrong with the modeling. You should use a OneToOneField between Employee and User. In essence an OneToOneField is a unique ForeignKey. It will however change some logic, such that user.employee will access the related Employee object, not a QuerySet of Employees:
class Employee(models.Model):
# ...
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='employee'
)
# ...
In your AccountView, you unified 'skills' with the skills of that employee, indeed:
class AccountView(TemplateView):
template_name = "profile.html"
def get_context_data(self, **kwargs):
context = super(AccountView, self).get_context_data(**kwargs)
context.update(
skills=Skill.objects.filter(employee__user=self.request.user).select_related('technology')
)
return context
You might want to use .select_related(..) here to prevent the so-called "N+1 problem" where for each skill, you will make an extra query.
So you can render the skills with:
{% for skill in skills %}
{{ skill.technology.name }}
{{ skill.level }}
{% endfor %}
or you can access is through:
{% for skill in request.user.employee.employee_skills.all %}
{{ skill.technology.name }}
{{ skill.level }}
{% endfor %}
although the above is less safe, since it is possible that a User has no related Employee object.
Your Employee model currently has a one to many relationship with a user
class Employee(models.Model):
"""Employee information."""
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='employee', unique=True)
according to your comment you need a one to one relation ship so you need to change this to use a OneToOneField instead of a ForeignKey
Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.
I'm using nested prefetching to link all my objects with each other and then pushing them to a template to show them.
My general setup: I have frameworks, categories and controls. A control is linked to a category, a category is linked to a framework. A category can also have a supercategory, in which case the category has a call to another category object. Every control also has an initial score, current score and a target score.
What I want to do is for every framework, for every supercategory, for every subcategory show every control with their scores.
Example:
Framework A
Super Category 1
Subcategory 1
Control 1
Initial
Current
Target
Control 2
...
Subcategory 2
Control 3
...
Super Category 2
Subcategory 3
Control 4
...
Framework B
...
I've already managed to do this by using a lot of nested prefetches.
My models:
# models.py
#==============[FRAMEWORKS]==============#
class Framework(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(null=True)
def __str__(self):
return self.name.replace(' ', '_')
class FrameworkCat(models.Model):
name = models.CharField(max_length=100)
identifier = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="optional identifier")
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
superCat = models.ForeignKey('self',
on_delete=models.CASCADE,
verbose_name="super category",
blank=True,
null=True)
hexColor = models.CharField(max_length=10,
null=True,
blank=True,
verbose_name="hex color")
def __str__(self):
return self.name
#==============[CONTROLS]==============#
class Control(models.Model):
title = models.CharField(max_length=250)
description = models.TextField()
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
category = models.ForeignKey(FrameworkCat,
on_delete=models.CASCADE,
verbose_name="related category",
null=True)
def __str__(self):
return self.title
class ProjectScore(models.Model):
project = models.ForeignKey(Project,
on_delete=models.CASCADE,
verbose_name="related project")
control = models.OneToOneField(Control,
on_delete=models.CASCADE,
verbose_name="related control")
framework = models.ForeignKey(Framework,
on_delete=models.CASCADE,
verbose_name="related framework")
score = models.IntegerField(default=-1)
current_score = models.IntegerField(default=-1)
target = models.IntegerField(default=-1)
def __str__(self):
return "Project Score"
My (testing) view:
# views.py
def testing_models(request):
def_data = default_data(request)
frameworks = Framework.objects.prefetch_related(Prefetch('frameworkcat_set',
queryset=FrameworkCat.objects.prefetch_related(Prefetch('frameworkcat_set',
queryset=FrameworkCat.objects.prefetch_related(Prefetch('control_set',
queryset=Control.objects.select_related('projectscore').order_by('id'),
to_attr='controls')).exclude(superCat=None),
to_attr='categories')).filter(superCat=None),
to_attr='supercategories')).all()
def_data['frameworks'] = frameworks
return render(request, 'testing_models.html', def_data)
And my template to show everything:
# templates/testing_models.html
{% for framework in frameworks %}
{% for supercategory in framework.supercategories %}
<p><strong>{{ supercategory.name }}</strong></p>
{% for subcategory in supercategory.categories %}
<p>{{ subcategory.name }}</p>
{% for control in subcategory.controls %}
<p>{{ control.title }}</p>
<p>{{ control.projectscore.score }}</p>
<p>{{ control.projectscore.current_score }}</p>
<p>{{ control.projectscore.target }}</p>
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
This all works correctly by executing 6 queries. Now, my main question is: is there a better way to fetch these objects and link them than using all these nested prefetches? Is there some other kind of syntax that I could be using that makes it easier to read and easier to modify? I have many more things I would like to link but I'm afraid the python statement would become too big and my overview would be lost.
Much appreciated!
I'm trying to sort related items in a template by a field in a model three ForeignKey relationships away. I'm assembling the data for the template in the view as proposed in another StackOverflow answer:
Sorting related items in a Django template
As far as I can tell, I copied the code from this as-is except for I had to change variable names. It doesn't throw an error, it just displays no list items in the HTML unordered list.
# checkout.html
{% for item in cart_items %}
<tr>
<td class="left">
{{ item.name }}
<ul>
{% for part in part_list %}
<li>{{ part.name }}
{% endfor %}
</ul></td>
</tr>
{% endfor %}
And the view...
# views.py
def checkout(request):
cart_items = get_cart_items(request)
itemCollection = []
for item in cart_items:
item.part_list = item.product.buildpart.all().order_by('product__family__type')
itemCollection.append(item)
return render(request, 'checkout.html', locals())
And the get_cart_items function:
# cart.py
def get_cart_items(request):
""" return all items from the current user's cart """
return CartItem.objects.filter(cart_id=get_cart_id(request))
As I said, the template and view are pretty much copies of the solution presented in the aforementioned StackOverflow article. One thing I thought was curious was that itemCollection[] from the view is never referenced in the template.
I believe the order_by clause ('product__family__type') is right only because it doesn't generate an error. But in case that is the problem or a part of it here is the chain of models I am attempting to navigate in that order_by clause:
We start from the shopping cart model (CartItem):
class Item(models.Model):
cart_id = models.CharField(max_length=50)
quantity = models.IntegerField(default=1)
product = models.ForeignKey(PartModel, unique=False)
class Meta:
abstract = True
class CartItem(Item):
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['date_added']
verbose_name = "Cart Item"
Through the 'product' field we get to the model holding our inventory and its self-referential BuildPart ManyToMany model:
class PartModel(models.Model):
family = models.ForeignKey(PartFamily)
name = models.CharField("Model Name", max_length=50, unique=True)
buildpart = models.ManyToManyField('self', through='BuildPart',
symmetrical=False, related_name='+')
class Build(models.Model):
build = models.ForeignKey(PartModel, related_name='+')
part = models.ForeignKey(PartModel, related_name='+')
quantity = models.PositiveSmallIntegerField(default=1)
class Meta:
abstract = True
unique_together = ('build', 'part')
def __unicode__(self):
return self.build.name + ' with ' + str(self.quantity) + ' * ' + \
self.part.family.make.name + ' ' + self.part.name
class BuildPart(Build):
pass
class Meta:
verbose_name = "Build Part"
From there we follow the 'family' field to the PartFamily model:
class PartFamily(models.Model):
make = models.ForeignKey(PartMake)
type = models.ForeignKey(PartType)
name = models.CharField("Family Name", max_length=30,
unique=True)
slug = models.SlugField(unique=True)
And lastly, we get to the model with the 'order' field, the one we wish to sort the related items by, PartType:
class PartType(models.Model):
name = models.CharField("Part Type", max_length=30, unique=True)
slug = models.SlugField(unique=True)
order = models.PositiveSmallIntegerField()
description = models.TextField(blank=True, null=True)
To recap, how do I get the shopping cart products' related items, and sort them by the 'order' field in the PartType model?
You have two errors, both in the template.
Firstly, you've put your items with the sorted relationship in a list called itemCollection, but in the template you're iterating over cart_item instead. This is a very good example of why you should be explicit about what variables you pass to the template, rather than relying on locals().
Secondly, you then iterate over part_list without defining it. You mean item.part_list.
I am building a form for a store that will allow clients to choose a price from a number of choices. The current Django template looks like so and works very well.
<select>
<option>{{ p.equipment_list.season_price.currency }} {{ p.equipment_list.season_price.daily }} per day.</option>
<option>{{ p.equipment_list.season_price.currency }} {{ p.equipment_list.season_price.weekly }} per week.</option>
<option>{{ p.equipment_list.season_price.currency }} {{ p.equipment_list.season_price.monthly }} per month.</option>
</select>
I have a product 'p' that is part of a group called Equipment List. This list has different pricing (season_price) depending on the time of year or through an sale offer. This allows maximum customizability and separation of tasks. Here are the models:
class SeasonPrice(models.Model):
name = models.CharField(_('Season Price'), max_length=300)
slug = models.SlugField(max_length=150, unique=True)
description = models.TextField(blank=True)
currency = models.ForeignKey(Currency)
daily = models.DecimalField(max_digits=10, decimal_places=2)
weekly = models.DecimalField(max_digits=10, decimal_places=2)
monthly = models.DecimalField(max_digits=10, decimal_places=2)
…
class EquipmentList(models.Model):
...
name = models.CharField(_('Equipment List'), max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
season_price = models.ForeignKey(SeasonPrice)
….
class Product(ImageModel):
...
equipment_list = models.ForeignKey(EquipmentList, related_name='Equipment')
name = models.CharField('Name', max_length=300)
slug = models.SlugField(max_length=150, unique=True)
description = models.TextField()
is_active = models.BooleanField(default=True)
quantity = models.IntegerField()
…
#models.permalink
def get_absolute_url(self):
return ('product_detail', (), {'product_slug': self.slug})
….
The form looks something like this:
class ProductAddToCartForm(forms.Form):
...
product_slug = forms.CharField(widget=forms.HiddenInput())
price = forms.ModelChoiceField(EquipmentList)
quantity = forms.IntegerField(widget=forms.TextInput(attrs={'size':'2', 'value':'1', 'class':'quantity'}),
error_messages={'invalid':'Please enter a valid quantity.'},
min_value=1)
...
And the View:
def show_product(request, product_slug, template_name="shop/product_detail.html"):
p = get_object_or_404(Product, slug=product_slug)
page_title = p.name
# need to evaluate the HTTP method
if request.method == 'POST':
postdata = request.POST.copy()
form = ProductAddToCartForm(request, postdata)
if form.is_valid():
cart.add_to_cart(request)
url = urlresolvers.reverse('show_cart')
return HttpResponseRedirect(url)
else:
form = ProductAddToCartForm(request=request, label_suffix=':')
form.fields['product_slug'].widget.attrs['value'] = product_slug
request.session.set_test_cookie()
return render_to_response("shop/product_detail.html", locals(), context_instance=RequestContext(request))
All the examples that I have seen of ModelChoiceField are one ForeignKey deep. From the above, I want to be able to chain-link 2 to 3 ForeignKeys and output a numeral string to be multiplied with the quantity the shopper wants and then place into a shopping cart.
Thanks
I don't think that ModelChoiceField is appropriate for the original <select> you show. You are choosing a currency/decimal combination, not a model instance. Probably, you want to build an ad-hoc ChoiceField.
myform.fields['price'].choices = (
('1::3.50', "EUR 3.50 per day"),
# ...
)
where 1::3.50 can be split() in clean/save to give the currency id and the amount string. Something like that.