Display User teams in template - python

I have 3 models - Project, Team and a CustomUser model. I'm trying to display a list of teams which a user is part of on the user's detail page, and display a list of users who are part of the project team on the project's detail page but I'm at a stand-still.
# project/users/models.py
class CustomUser(AbstractUser):
name = models.CharField(max_length=255)
# Relationship Fields
team = models.ManyToManyField(
'users.Team',
related_name="teams",
)
class Team(models.Model):
# Relationship Fields
project = models.OneToOneField(
'projects.Project',
on_delete=models.CASCADE, related_name="projects",
)
# project/projects/models.py
class Project(models.Model):
name = models.CharField(max_length=255)
project/projects/templates/projects/project_detail.html
{% for user in project.team.user.all %}
{{ user.name }}
{% endfor %}
I've tried variations of the above such as
{% for user in users.teams.projects.all %}
{{ user.name }}
{% endfor %}
but I can't seem to make anything show. I think I'm doing something simple wrong - I've read through the docs for displaying ManyToManyFields but I'm at a loss! Can anybody point me in the right direction?

im not sure but i think related_name are missed used in this situation:
class Team(models.Model):
# Relationship Fields
project = models.OneToOneField(
'projects.Project',
on_delete=models.CASCADE, related_name="projects",
)
this means that in one object of the class Project will have an attribute with the name projects that will be a reference to the teams. I believe you want:
class Team(models.Model):
# Relationship Fields
project = models.OneToOneField(
'projects.Project',
on_delete=models.CASCADE, related_name="team",
)
So you will be able to call project.team.
Changing your code:
# project/users/models.py
class CustomUser(AbstractUser):
name = models.CharField(max_length=255)
# Relationship Fields
team = models.ManyToManyField(
'users.Team',
related_name="customers",
)
class Team(models.Model):
# Relationship Fields
project = models.OneToOneField(
'projects.Project',
on_delete=models.CASCADE, related_name="team",
)
class Project(models.Model):
name = models.CharField(max_length=255)
So in the template now you could:
{% for user in project.team.customers.all %}
{{ user.name }}
{% endfor %}

Related

Django - Can not join 2 models

Problem: Joining 2 models in Django.
Error: Error during template rendering. Direct assignment to the reverse side of a many-to-many set is prohibited. Use entity_id.set() instead.
I have read through all the threads on SO. Tried all the suggested solutions, read the Django documentation and think I just must be fundamentally misunderstanding something. Any help would be much appreciated.
I have 2 models. Entity and File.
An Entity can have multiples Files but each File only has 1 Entity.
The primary keys of each table are just auto incrementing integers. Therefore I want to join column entity_id from File with entity_id from Entity. According to the documentation I have set entity_id in File as a ForeignKey. And I have set entity_id as unique in Entity
class Entity(models.Model):
pk_entity = models.AutoField(primary_key=True)
entity_id = models.IntegerField(blank=True, null=True, unique=True)
name = models.CharField(blank=True, null=True)
class Meta:
managed = False
db_table = 'entities'
class File(models.Model):
pk_file = models.AutoField(primary_key=True)
filename = models.CharField(blank=True, null=True)
entity_id = models.ForeignKey(Entity, on_delete= models.CASCADE, to_field='entity_id')
The view is just trying to render this. I have tried using .all() rather than select_related() but no data renders.
class TestListView(ListView):
queryset = File.objects.select_related()
template_name = "operations/files/test_list.html"
And this is the html:
{% extends "base.html" %}
{% block content %}
<div>
<div>
<ul>
{% for x in object_list %}
<li>
{{x}}
</li>
{% empty %}
<p>Empty</p>
{% endfor %}
</ul>
</div>
</div>
{% endblock %}
When using select_related you should pass your field name to be selected.
Try this:
class TestListView(ListView):
queryset = File.objects.select_related("entity").all()
template_name = "operations/files/test_list.html"

Retrieving metadata from a post, then sorting posts by said metadata in django

I have two interconnected models in my blog app; Category and Post. The blog front page displays a list of posts and their corresponding metadata, like it should; fairly standard stuff.
Aside from displaying the posts on the front page, they're also displayed on the individual user's profile page in short form (just the category and the headline).
What I'm interested in doing is sorting all the posts that belong in a category, however the only way I've managed to make it work is something like this:
NEWS
some title
NEWS
another title
PYTHON
another arbitrary title
NEWS
yet another title
I'd like to sort it thusly instead:
NEWS
some title
another title
yet another title
PYTHON
another arbitrary title
Alas, my mind keeps turning into a bowl of spaghetti when I try to come up with a method, so without further ado; how should I go about this bit?
I reckon that there's something off with calling the category from the post's metadata only to try and categorize the posts via the retrieved data, but aside from that, I'm somewhat lost.
Here's the template snippet from user_profile.html:
{% if user.post_set.exists %}
<p>
{% for post in user.post_set.all|dictsortreversed:"date_posted" %}
<span style="margin-right: 5px; padding: 3px 6px; border-radius:12px; color:#FFF; background-color:#FFA826;">{{ post.category }}</span><br/>
<a style="margin-left:3px;" href="{% url 'blog:post-detail' post.slug %}">{{ post.title|truncatechars_html:30 }}</a><br/>
{% endfor %}
</p>
{% endif %}
The models:
class Category(models.Model):
class Meta:
verbose_name = 'category'
verbose_name_plural = 'categories'
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=60)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.CASCADE)
content = RichTextUploadingField(
external_plugin_resources=[(
'youtube',
'/static/ckeditor/ckeditor/plugins/youtube/',
'plugin.js'
)],
blank=True,
null=True,
)
date_posted = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(auto_now=True)
slug = models.SlugField(max_length=70, blank=True, null=True, help_text='<font color="red">don\'t. touch. the. slug. field. unless. you. mean. it.</font> (it will auto-generate, don\'t worry.)')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post-detail', kwargs={'slug': self.slug})
And finally the view which relate to the post_list.html:
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = '-date_posted'
paginate_by = 6
Should I be doing it in a different manner altogether, I wonder? And if so, what would be considered 'best practice'?
Thank you :)
You can add the ordering in your model:
class Post(models.Model):
...
class Meta:
ordering = ['category', '-date_posted']
See the documentation for more details:
update
Maybe its better to use custom manager for this:
from django.db import models
class CustomManager(models.Manager):
# subclass model manager
def custom_category_dict(self, **kwargs):
# add a new method for building a dictionary
nDict = dict()
for i in self.get_queryset().filter(**kwargs): # filter queryset based on keyword argument passed to this method
current_list = nDict.get(i.category.name, [])
current_list.append(i)
nDict.update({i.category.name: current_list})
return nDict
class Posts(models.Model):
# override posts model with manager
objects = CustomManager()
Usage:
# view
class PostListView(ListView):
...
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
context['category_wise_sorted_posts'] = Posts.objects.custom_category_dict() # you can pass filter logic as well, like Posts.objects.custom_category_dict(author_id=1)
return context
# template
{% for category, posts in category_wise_sorted_posts.items %}
<!-- Or {% for category, posts in user.posts_set.custom_category_dict.items %} -->
{{ category }}
{% for p in posts %}
{{ p.title }}
{% endfor %}
{% endfor %}

Django: How to iterate over two one-two-many table relationships?

I am trying to build a simple web page that queries three tables. There is a Company table that has a one-to-many relationship with a Position table, as well as a one-to-many relationship with a Project table.
The goal is to have the page display a given company once, along with all positions and and projects associated with said company. Then, move on to display the next company, any positions held there and projects completed.
Below is the closest I've come to getting this right. But, the obvious problem is that if there is more than one project associated with a given company, you'll see that company listed more than once.
I'm new to Django, so in the interest of learning, I wanted to beat my own head sufficiently hard before asking for help; but I could really use some fresh ideas at this point.
Also: I can see how a nested for loop might work here, but I'm just not clear on how the mechanics of that would work with the query, and then within the template.
Models:
from django.db import models
class Company(models.Model):
company_id = models.AutoField(primary_key=True)
company_name = models.CharField(max_length=20)
company_logo = models.ImageField(upload_to='images/')
def __str__(self):
return self.company_name
class Position(models.Model):
position_id = models.AutoField(primary_key=True)
position_title = models.CharField(max_length=55)
company_id = models.ForeignKey('professional.Company',
on_delete=models.CASCADE,
blank=True,
null=True)
begin_date = models.DateField()
end_date = models.DateField()
def __str__(self):
return self.position_title
class Project(models.Model):
project_id = models.AutoField(primary_key=True)
project_name = models.CharField(max_length=55)
company_id = models.ForeignKey('professional.Company',
on_delete=models.CASCADE,
blank=True,
null=True)
project_description = models.CharField(max_length=500)
project_image = models.ImageField(upload_to='images/')
def __str__(self):
return self.project_name
View:
from django.views.generic import TemplateView, ListView
from professional.models import Company
class ProfessionalHome(TemplateView):
template_name = 'professional/professional_home.html'
class TechnologyListView(ListView):
template_name = 'professional/__technology.html'
context_object_name = 'technology_list'
def get_queryset(self):
return Company.objects.values('company_name','position__position_title', 'project__project_name')
HTML and template:
{% for job in technology_list %}
<h1>{{job.company_name}}</h1>
<h1>Position: {{job.position__position_title}}</h1>
<h1>project: {{job.project__project_name}}</h1>
{% endfor %}
Instead of values in get_queryset method, you can return the actual queryset and then iterate over it to build your view.
def get_queryset(self):
return Company.objects.all()
Then in your template:
{% for job in technology_list %}
<h1>{{job.company_name}}</h1>
{% for position in job.position_set.all() %}
<h1>Position: {{position.position_title}}</h1>
{% endfor %}
{% for project in job.position_set.all() %}
<h1>project: {{project.project_name}}</h1>
{% endfor %}
{% endfor %}
If you want to iterate over companies, then you should use the Company model as the basis for your view, not Technology. Also, you should avoid values and values_list unless you know you have a good reason, which you don't here. You can use prefetch_related() to reduce the number of reverse queries. So:
class TechnologyListView(ListView):
def get_queryset(self):
return Company.objects.all.prefetch_related('project','position')
...
{% for company in company_list %}
<h1>{{company.company_name}}</h1>
{% for position in company.position_set.all %}
<h1>Position: {{ position.position_title }}</h1>
{% endfor %}
{% for project in company.project_set.all %}
<h1>project: {{ project.project_name }}</h1>
{% endfor %}
{% endfor %}
(Note, you should avoid giving your ForeignKey fields names ending in "_id". The Django field refers to the entire Company, not the ID; the fields should be called just company. The underlying database will be suffixed with _id anyway. Also, you don't need to use model_name prefixes on all your fields; it will be obvious from the object they are accessed on.)

Display data from models in website

I am new to Django. I want to display latest data entered from models to the website.
models.py
class Service(models.Model):
service_name = models.CharField(max_length=200)
service_code = models.IntegerField(default=0, unique=True)
views.py
def Latest(return):
latest_services = Service.objects.order_by('service_name')
index.html
{{ service_name }}
Latest Services Goes here
When I run the code nothing is displayed!
You need to iterate over the queryset:
<ul>
{% for service in latest_services %}
<li>{{ service.service_name }}</li>
{% endfor %}
</ul>
Anyway, if you want to display the latest entries, you should add a new field to your model with the date. For example:
class Service(models.Model):
created_on = models.DateTimeField(auto_now=True)
service_name = models.CharField(max_length=200)
service_code = models.IntegerField(default=0, unique=True)
And then in your query:
latest_services = Service.objects.order_by('created_on')

How to display fields of a M2M relation

I have this Django model:
#encoding:utf-8
from django.db import models
from django.contrib.auth.models import User
from django.contrib import admin
# Create your models here.
class Profile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='user')
follows = models.ManyToManyField(User, related_name='follows', symmetrical=False, blank=True)
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatar', blank=True)
website = models.CharField(max_length=100, blank=True)
place = models.CharField(max_length=100, blank=True)
def __unicode__(self):
return unicode(self.user)
admin.site.register(Profile)
admin.autodiscover()
Then, I have this view:
def profile(request, user_id):
user = get_object_or_404(Profile, user=user_id)
return render_to_response('user_view.html', {'user':user,})
Now, in user_view.html I display the 'User' data (username, avatar, website, etc):
{{user.user_id}}
{{user.user}}
{{user.website}}
{{user.avatar.url}}
But, also I need to display the username, avatar and website of the users I follow. I did this:
{% for element in user.follows.all %}
{{element.user}}
<img src="{{element.avatar.url}} />
{% endfor %}
But, instead of display the user's data, it shows this:
<django.db.models.fields.related.RelatedManager object at 0x022F34F0>
But if I do this:
{% for element in user.follows.all %}
<p>{{element}}</p>
{% endfor %}
It shows perfectly the user's name, but I still cannot display the website or the avatar. How can I do this?
I think you would try
{% for element in user_data.follows.all %}
<p>{{element.username}}</p>
<p>{{element.profile.website}}</p>
<p>{{element.profile.avatar}}</p>
{% endfor %}
element is an instance of User and not an instance of Profile.
But you can still retrieve the associated Profile instance by writing
element.profile
because it's a One-To-One relationship (OneToOneField or ForeignKey(unique=True))

Categories