DJANGO: Showing many-to-many additional fields in template - django

I have the following situation: A project can belong to multiple departments, Employees are assigned roles to multiple projects. How do I show the roles field in a template? employees.role shows blank...
MODELS
class Projects(models.Model):
name = models.CharField(max_length=20)
class Department(models.Model):
name = models.CharField(max_length=20)
class Employees(models.Model):
fname = models.CharField(max_length=15)
class Departmentprojects(models.Model):
department = models.ForeignKey(Department)
projects = models.ForeignKey(Projects)
members = models.ManyToManyField(Employee, through='Membership')
class Membership(models.Model):
departmentprojects = models.ForeignKey(Departmentprojects)
employee = models.ForeignKey(Employee)
role = models.CharField(max_length=20) #i want to show this field in a template
VIEW
def department_detail(request, company_id):
department = get_object_or_404(Department, pk=department_id)
return render_to_response('test/detail.html', {'department': department})
TEMPLATE
<h1>{{ department.name }}</h1>
{% for projects in department.departmentprojects_set.all %}
<h2>{{ projects.projects }}</h2>
<ul>
{% for employees in projects.members.all %}
<li>{{ employee }} | {{ employee.role }}</li>
{% endfor %}
</ul>
{% endfor %}

Iterate over the "through" model instead of the target model:
{% for membership in projects.membership_set.all %}
<li>
{{ membership.employee }} | {{ membership.role }}
</li>
{% endfor %}

Related

Modeling a restaurant menu with django

I am creating a website with a collection of menus from restaurants in my town (since none of them seem to be on grubhub or the internet). I am having trouble creating a model for this. As you know every restaurant menu has sections(I.e Appetizers, Chicken, Steak) and entries under each section(I.e under Appetizers: Mozzarella Sticks, Nachos, etc.) I am trying to create a Menu model so that each section of the menu and all of its entries can automatically fill a template:
<h1>{{section}}</h1> <!--I.e:"Appetizers"-->
<p>{{food}} </p><!--I.e:"Mozzarella Sticks"-->
<p>{{ food_details }}</p>
With the above template, I can use a loop to loop through each section, then another inner loop to loop through each food and food_details belonging to that specific section, but I am not sure how to model this properly:
from django.db import models
class Restaurant(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
phoneNumber = models.CharField(max_length=10)
def __str__(self):
return "%s the place" % self.name
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
# not sure how to build menu fields
#if I do the following each menu will only have one of these fields, which will not work:
section = models.CharField(max_length=50)
food = models.CharField(max_length=50)
food_details = models.CharField(max_length=200)
How can I create a model of a menu that has multiple section's and multiple food and food_details entries under each section? I hope this made sense, let me know if there is anything I can add and thanks in advance for any help.
You could try something like this:
# models.py
FOOD_TYPES = (
('appetizer', 'appetizer'),
('entree', 'entree'),
('dessert', 'dessert'),
)
class FoodItem(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=100)
type = models.CharField(max_length=100, choices=FOOD_TYPES)
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
food_items = models.ManyToManyField(FoodItem)
In a view:
# views.py
class Restaurant(TemplateView):
model = Restaurant
template_name = 'name'
...
def get_context_data
context = super(Menu, self).get_context_data(**kwargs)
restaurant = Restaurant.objects.get(name='McDonalds')
context['restaurant'] = Restaurant.objects.get(name='McDonalds')
context['menu'] = Menu.objects.get(restaurant=restaurant)
return context
In the template:
# template.html
<h1>{{ restaurant.name }}</h1>
<h2>Menu</h2>
{% for item in menu.food_items %}
{% if item.type = 'appetizer' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No appetizers</p>
{% endif %}
{% if item.type = 'entree' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No entrees</p>
{% endif %}
{% if item.type = 'dessert' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No dessert</p>
{% endif %}
{% endfor %}

How can I organize a list of fields based on another field?

I am trying to show a list of items organized by their category, with their respective category name directly above it in bold. For example:
Category 1
List item 1
List item 2
Category 2
List item 3
However, here is what the code currently does:
Category 1
List item 1
List item 2
List item 3
Category 2
List item 1
List item 2
List item 3
The two model classes involved taken from /models.py:
class Model(models.Model):
model_number = models.CharField('Model Number', max_length = 50)
manufacturer = models.ForeignKey('Manufacturer', on_delete = models.SET_NULL, null = True)
category = models.ForeignKey('Category', on_delete = models.SET_NULL, null = True)
description = models.TextField(max_length = 1000, help_text = "Enter brief description of product", null = True) #TextField for longer descriptions
def __str__(self):
return f'{self.model_number}..........{self.description}'
def get_absolute_url(self):
#Returns the url to access a particular location instance
return reverse('model-detail', args=[str(self.id)])
class Category(models.Model):
category = models.CharField('Equipment Type', max_length = 50,
help_text = "Enter general category of equipment")
class Meta:
verbose_name_plural = "categories" #default would have shown as "Categorys" on admin page
def __str__(self):
return self.category
/model_list.html
{% extends "base_generic.html" %}
{% block content %}
<div style="margin-left:20px; margin-top:20px">
<h1>Model list</h1>
</div>
{% if model_list %}
{% for category in model_list %}
<li><strong>{{ category.category }}</strong></li>
<ul>
{% for model in model_list %}
<li>
{{ model.model_number }}..........{{ model.description }}
</li>
{% endfor %}
</ul>
{% endfor %}
{% else %}
<p>There is no equipment in the database</p>
{% endif %}
{% endblock %}
For ForeignKey fields you can access one "Model"'s attributes from another's:
{% for model in models %}
{{ model.category.category }}
{{ model.category.help_text }}
{% endfor %}
Essentially - think of the field's for manufacturer and category that you have above in your Model as fields that are storing objects - once you get that field - your variable isn't a string or a integer, but it's an instance of the Category model. Then you can begin to select the attributes for that model, that is to say model.category is an instance of the Category object.
It looks like, from the way you have organised your models, that what you want to achieve is a little tricky. I would maybe advise looking at folding your categorisation of all your models in an array of objects of objects:
in views.py:
models = [ { 'category': 'categoryName', 'objects': [ SomeModelInstance1 , ... ] } ]
Then:
{% for model in models %}
model.category
{% for object in model.objects.all %}
{{ object.name }}
{% endfor %}
{% endfor %}
Let me know if this points you in the right direction...happy to help in the comments.

select backward associated in django

I'm wrinting a Django project.
In courses/models.py
class Category(models.Model):
title = models.CharField(max_length=50)
class Language(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
class Course(models.Model):
name = models.CharField(max_length=250)
language = models.ForeignKey(Language, on_delete=models.CASCADE)
I want to get list of all Category and then loop through each Language of specified category.
class Courses(ListView):
template_name = 'courses/index.html'
model = Course
context_object_name = 'courses'
def get_context_data(self, **kwargs):
context = super(Courses, self).get_context_data(**kwargs)
categories = Category.objects.all()
context['categories'] = categories
return context
in template courses/index.html I want to show the list of languages based on category
{% for category in categories %}
{{ category.title }}
<li>lis of languages in this category</li>
{% endfor %}
How to loop on backward associated data?
Django creates a relation that is accessible in the templates through the modelname_set key.
In your case, you'd have to iterate over:
category.language_set.all
{% for category in categories %}
{{ category.title }}
{% for language in category.language_set.all %}
<li>{{ language.title }}</li>
{% endfor %}
{% endfor %}
_set does this work.
eg. in your case this code must work:
{% for language in category.language_set.all %}
{{ language.title }}
{% endfor %}

Django model relationships in views and templates

I'm working on multi-user rss reader. I want to limit display of posts only to those which are unread. I've managed to do this in my single "feed" view as below, but I can't figure out how to do the same in multiple feed aka "category" view.
I've been trying something like here https://docs.djangoproject.com/en/1.5/topics/db/queries/#spanning-multi-valued-relationships but it didn't work for me
Should I change my "category" view code or template code? and if so how would you go about it?
thanks!
-S
models
class UserCategory(models.Model):
name = models.CharField(unique=False, max_length=64)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='name', always_update='True', unique_with='user')
class Feed(models.Model):
feed_url = models.URLField(unique=True)
default_title = models.CharField(max_length=64, blank=True)
link = models.URLField(blank=True)
class UserFeed(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=64)
category = models.ForeignKey(UserCategory)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='title', always_update='True', unique_with='user')
class Post(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=256)
content = models.TextField()
link = models.URLField(max_length=512)
class ReadPost(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
views
def feed(request, user_feed_slug):
user_feed = get_object_or_404(UserFeed.objects.filter(slug=user_feed_slug, user=request.user))
read_post = ReadPost.objects.filter(user=request.user).values_list('post')
posts = Post.objects.select_related().filter(feed=user_feed.feed).exclude(id__in=read_post)
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory.objects.filter(slug=user_category_slug, user=request.user))
templates
feed
{% for post in posts %}
{{ post.title }}
{% endfor %}
category
{% for feed in user_category.userfeed_set.all %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}
You can write custom template filter, i.e:
#register.filter
def unread(posts, read_posts):
return posts.exclude(id__in=read_posts)
(before you must pass read_post to category template context).
Try this queryset:
def category(request, user_category_slug):
user_category = get_object_or_404(UserCategory, slug=user_category_slug,
user=request.user))
feeds = UserFeed.objects.filter(category__slug=user_category_slug, user=request.user)\
.prefetch_related('feed__post_set')
then in your template:
{% for feed in feeds %}
{{ feed.title }}
{% for post in feed.feed.post_set.all %}
{{ post.title }}
{{ post.content }}
{% endfor %}
{% endfor %}

Group django formset into groups based on foreign key

I have a simple setup of InventoryItems and Categories. I have a formset of InventoryItems but want to split up the items based on the FK Category, I don't need or want an inline form set.
Simplified version of what I have
class Category(models.Model):
name = models.CharField(max_length=255)
inventory = models.BooleanField(default=False)
class Inventory(models.Model):
name = models.CharField(max_length=255)
quantity = models.IntegerField()
category = models.ForeignKey(Category)
def viewOfForm(request):
categories = Category.objects.filter(inventory=True)
InventoryFormset = modelformset_factory(Inventory, can_delete=True, extra=1)
formset = InventoryFormset(request.POST or None, queryset=Inventory.objects.filter(category__inventory=True))
return render_to_response('template.html', locals())
What I would like to do in the template
{% for category in categories %}
<fieldset class="collapse">
<h2>{{ category.name }}</h2>
{% for form in formset %}
{% if form.category == category %}
{{ form }}
{% endif %}
{% endfor %}
</fieldset>
{% endfor %}
You only need a small change to get this working; use form.instance.category in your if template tag:
{% if form.instance.category == category %}