I am trying to make a user panel in which each user's profile info (like avatar, joined date, etc.) are being displayed along with their posts. Here is the view that render the threads:
def topic(request, topic_id):
"""Listing of posts in a thread."""
posts = Post.objects.select_related('creator') \
.filter(topic=topic_id).order_by("created")
posts = mk_paginator(request, posts, DJANGO_SIMPLE_FORUM_REPLIES_PER_PAGE)
topic = Topic.objects.get(pk=topic_id)
topic.visits += 1
topic.save()
return render_to_response("myforum/topic.html", add_csrf(request, posts=posts, pk=topic_id,
topic=topic), context_instance=RequestContext(request))
The Topic model is:
class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=10000, null=True)
forum = models.ForeignKey(Forum)
created = models.DateTimeField()
creator = models.ForeignKey(User, blank=True, null=True)
visits = models.IntegerField(default = 0)
And the UserProfile model:
class UserProfile(models.Model):
username = models.OneToOneField(User)
name = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
country = models.CharField(
max_length=20, choices= COUTNRY_CHOICES, blank=True)
avatar = ImageWithThumbsField(), upload_to='images', sizes=((32,32),(150,150),(200,200)), blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, blank=True)
The problem is how best to join these two tables so that userprofile fields can be displayed in topic.html along with username?
Add them to context since you already have a database relation Users and Topics.
# add this to context
topic = Topic.objects.get(pk=topic_id)
creator = topic.creator.get().profile # This pulls the user object from creator field
context['creator'] = creator # Add to context
Now you can use the 'creator' context to pull fields
<h1>{{ creator.name }}</h1>
as for the avatar, if you have your media root set in settings you simply use an
<img src="/media/images/{{ creator.avatar }}">
Oh and also you can save alot of time by using ListView and DetailView part of Django's class based views.
Sorry forgot to mention you should add a related name to your one to one,
username = OneToOneField(User, related_name='profile')
Related
I am building a web-application for my senior design project with Python and Django. I have a user model that is able to read/write articles to display on the website. I have some tasks I want to accomplish.
I want to make it so that if an article is accessed (read) by a user, it is indicated for only that user that the article has been previously accessed. If I were to log into a brand new user account, the same article wouldn't be indicated as "accessed" for the new account.
How would I be able to present on the front-end side that the article has been viewed by the user logged in? (ie: make the article title bolded or a different color to indicate its been already visited)
Below are my models and views:
User model
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
email = models.EmailField(unique=True, max_length=255, blank=False)
university = models.CharField(max_length=200, null=True, blank=True)
newsletter_subscriber = models.BooleanField(default=False)
is_email_verified = models.BooleanField(default=False)
is_staff = models.BooleanField(
default=False,
help_text=(
'Designates whether the user can log into '
'this admin site.'
),
)
is_active = models.BooleanField(
default=True,
help_text=(
'Designates whether this user should be '
'treated as active. Unselect this instead '
'of deleting accounts.'
),
)
date_joined = models.DateTimeField(default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
Article model
class Article(models.Model):
user = models.ForeignKey(
User, on_delete=models.DO_NOTHING, null=True, blank=True)
title = models.CharField(max_length=200, null=True, blank=False)
author = models.CharField(max_length=200, null=True, blank=False)
year = models.CharField(max_length=200, null=True, blank=False)
journal = models.CharField(max_length=200, null=True, blank=False)
description = models.TextField(null=True, blank=True)
URL = models.CharField(max_length=200, null=True, blank=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class MetaData:
ordering = ['-created']
Article detail view
class ArticleDetail(LoginRequiredMixin, DetailView):
model = Article
context_object_name = 'articles'
template_name = 'home/article_detail.html'
Thank you!
You could create an extra table.
class ArticleSeenRecord(models.Model):
user = models.ForeignKey("django.contrib.auth.models.User", on_delete=models.CASCADE)
article = models.ForeignKey(Article, on_delete=models.CASCADE)
And then in your article view, create a new record when one doesn't exist, for that article combined with the authenticated user.
class ArticleDetail(LoginRequiredMixin, DetailView):
model = Article
context_object_name = 'articles'
template_name = 'home/article_detail.html'
def get_object(self, queryset=None):
obj = super().get_object(queryset)
record, created = ArticleSeenRecord.objects.get_or_create(user=self.request.user, article=obj)
return obj
class Article(models.Model):
...
def seen_by_user(self, user):
return self.atricleseenrecord_set.objects.filter(user=user).exists()
I added the extra function here. You will also need to add a template tag which you can ideally copy from this example
#register.simple_tag
def article_seen_by_user(article, user):
return article.seen_by_user(user)
For further guidance on how to use and register custom template tags, please refer to this page of the documentation:
https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/
Specifically this section:
https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#django.template.Library.simple_tag
I have two models, ChatBox and Message. I want to loop through all chats and display them, and I want to display a count of unseen messages (Message model is in a foreign key relation) for each chat.
Could anyone please help me to do this since I ve been strugling with it for few hours.
Firstly I wanted to pass each object from the loop to django filters/tags and add a count of unseen messages to it, but I got advised to use objects.annotation. However, i can not find ways to implement none of these.
Here is my view that displays inbox:
class InboxView(LoginRequiredMixin, ListView):
model = ChatBox
template_name = 'chat/inbox.html'
def get_queryset(self):
# getting all chats for a request.user
object_list = ChatBox.objects.filter(Q(user1=self.request.user) \
| Q(user2=self.request.user)).all()
return object_list
And here are my models:
class ChatBox(models.Model):
user1 = models.ForeignKey(CustomUser,
on_delete=models.CASCADE, related_name='user1')
user2 = models.ForeignKey(CustomUser,
on_delete=models.CASCADE, related_name='user2')
slug = models.SlugField(_("Slug"), max_length=255, unique=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Message(models.Model):
chat = models.ForeignKey(ChatBox, on_delete=models.CASCADE)
sender = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='sender')
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
seen = models.BooleanField(default=False)
My site simply works like this: every Manager can have some SubManagers, those SubManagers can have some Agents (so the Agents are indirectly related to the Manager, see models.py to understand better the relations between them). I want to show in the Manager's profile page (see views.py) all the MembershipCard created by his/her related Agents. I'm trying to implement a filter to search, for example, cards created by a specific Agent, i'm able to do this but i would like to show in the dropdown only the Agents related to the Manager, the dropdown list now shows all Agents in the database
models.py
class StandardProfile(models.Model):
name = models.CharField(max_length=200, null=True)
surname = models.CharField(max_length=200, null=True)
phone_number = models.CharField(max_length=200, null=True)
class Meta:
abstract = True
class Manager(StandardProfile):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
class SubManager(StandardProfile):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
manager = models.ForeignKey(Capo, null=True, on_delete = models.SET_NULL)
class Agent(StandardProfile):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
manager = models.ForeignKey(Manager, null=True, on_delete = models.SET_NULL)
subManager = models.ForeignKey(SubManager, null=True, blank=True, on_delete = models.SET_NULL)
class MembershipCard(models.Model):
agent = models.ForeignKey(Agent, null=True,blank=True, on_delete = models.SET_NULL)
client = models.ForeignKey(Client, null=True,blank=True, on_delete = models.SET_NULL)
creation_date = models.DateTimeField(auto_now_add=True, null=True)
activation_date = models.DateTimeField(null=True,blank=True)
expiration_date = models.DateTimeField(null=True,blank=True)
views.py
#login_required(login_url='login')
def profilePage(request, pk): #www.mysite.com/profilePage/<pk>
user = User.objects.get(id=pk) #getting the user from <pk>
cards = MembershipCard.objects.filter(agent__manager=user.manager)
myFilter = MembershipCardFilter(request.GET,queryset=cards,user=user)
cards = myFilter.qs
#page_obj is used for Pagination, and contains the cards, i removed this part of code for better readability, can add it if needed
context = {'page_obj': page_obj,"user": user,"myFilter":myFilter}
return render(request, 'polls/profilePage.html',context)
filters.py
class MembershipCardFilter(django_filters.FilterSet):
class Meta:
model = MembershipCard
fields = ['agent','agent__subManager']
exclude = ['creation_date']
By reading answers to similar questions i think i have to modify the __init__ method in the CardFilter class, i've tried to adapt some answers to my case but it didn't work for some reasons . Any anser/comment is appreciated!
PS: I don't know if the title is clear, feel free to suggest a better one
You can try feeding the agent dropdown during init like (not tested!):
class MembershipCardFilter(django_filters.FilterSet):
agent= django_filters.ModelChoiceFilter(
queryset=Agent.objects.none(),
)
class Meta:
model = MembershipCard
fields = ['agent','agent__subManager']
exclude = ['creation_date']
def __init__(self, *args, **kwargs):
user = kwargs.get("user")
agents = Agent.objects.filter(manager__user=user)
super().__init__(*args, **kwargs)
self.filters["agent"].queryset = agents
i'm new with Django and as I read the code, I don't understand the message_set attribute of Django model(called Room):
def room(request, pk):
room = Room.objects.get(id=pk)
**room_messages = room.message_set.all()**
participants = room.participants.all()
portion of Models:
class Room(models.Model):
host = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
participants = models.ManyToManyField(
User, related_name='participants', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Message(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
body = models.TextField()
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
If you define a ForeignKey from Message to Room, Django will add a relation in reverse to the from the Room model to its related Messages. By default this relation is named modelname_set with modelname the name of the origin of the model. You can specify another name by overriding the related_name=… parameter [Django-doc].
If you thus access the relation in reverse, you get all Message objects with room as there room, an equivalent query to room.message_set.all() is thus Message.objects.filter(room=room).
I created models called Interview, Users, Interview_interviewer like wise...
Interview_interviewer table has foreign keys from other models.
I just want to save data from both 2 tables to Interview_interviewer(Without django forms) table which is many to many table. So I just created the views and template for it. When button clicks it save the Interviewers to table along side with the interview. But when do it, It gave me and error called "User matching query does not exist".
/home/govinda/DMG/test3/myapp/views.py in hod_inter_interviewer_2
usr = User.objects.get(id=pid)
What should I do?
class Interview(models.Model):
Time = models.TimeField()
Date = models.DateField()
Venue = models.ForeignKey('Venue')
HOD = models.ForeignKey(User)
Vacancy = models.ForeignKey('Vacancy', on_delete=models.CASCADE)
Department = models.ForeignKey(Department, on_delete=models.CASCADE)
InterviewType = models.ForeignKey(InterviewType, on_delete=models.CASCADE)
Interviewer_Review = models.TextField(blank=True, null=True)
HOD_Review = models.TextField(blank=True, null=True)
HR_Review = models.TextField(blank=True, null=True)
NoOfPasses = models.PositiveIntegerField(blank=True, null=True)
NoOfFails = models.PositiveIntegerField(blank=True, null=True)
NoOfOnHolds = models.PositiveIntegerField(blank=True, null=True)
InterviewNo = models.IntegerField(blank=True, null=True)
Post = models.ForeignKey(Post, on_delete=models.CASCADE)
and
class Users(models.Model):
User = models.OneToOneField(User)
FullName = models.CharField(max_length=100)
Post = models.ForeignKey(Post)
UPhoto = models.FileField(upload_to=User_directory_path,null = True,blank=True)
Department = models.ForeignKey(Department)
UserRole = models.ForeignKey(UserRole)
def __str__(self):
return u'{}'.format(self.User)
and
class Interview_Interviewer(models.Model):
Interview = models.ForeignKey(Interview)
Interviewer = models.ForeignKey(User)
def __str__(self):
return u'{}'.format(self.Interviewer)
views are...
def hod_pre_interviwer_list(request, iid):
inter = Interview.objects.get(id=iid)
a = UserRole.objects.get(Role="Interviewer")
viewer = Users.objects.filter(UserRole=a.id)
return render(request, 'hod_inter_create_2.html', {'viewer': viewer, 'inter': inter, 'a':a})
def hod_inter_interviewer_2(request, iid, pid):
inter = Interview.objects.get(id=iid)
usr = User.objects.get(id=pid)
a = UserRole.objects.get(Role="Interviewer")
viewer = Users.objects.filter(UserRole=a.id)
usr_id = Users.objects.get(User=a.id)
inter_id = inter
person_id = usr_id
form = Interview_Interviewer(Interview=inter_id, Interviewer=person_id)
form.save()
return render(request, 'hod_inter_create_2.html', {'viewer': viewer, 'inter': inter})
urls are...
urlpatterns = [
url(r'^hod/hod_vacancy/test/part2/inter_list/(\d+)/$', hod_pre_interviwer_list, name="inter1"),
url(r'^hod/hod_vacancy/test/part2/inter_list/(\d+)/(\d+)/$', hod_inter_interviewer_2, name="inter2"),
]
template is...
<a type="submit" class="btn btn-primary" href="/hod/hod_vacancy/test/part2/inter_list/{{ inter.id }}/{{ viewer.id }}">Add</a>
Try using named groups in your url patterns
urlurl(r'^hod/hod_vacancy/test/part2/inter_list/?P<iid>[0-9]+)/?P<pid>[0-9]+/$', hod_inter_interviewer_2, name="inter2"),
If that doesn't work then i suggest trying User.object.get(pk=pid) as in most doc examples.
And make sure that there is a user with that id (iid) in the url.
You should also use get_object_or_404 for getting any single object from a model in the view as it gives a more user friendly and appropriate error.