I'm a little confused by the Django lingo. So I have 3 models: Post, UserProfile(User), Favorite. Favorite keeps track of which Posts a User has favorited.
Post--->Favorite<---User/UserProfile
Favorite model:
class Favorite(models.Model):
user = models.ForeignKey(User, unique=False)
post = models.ForeignKey(Post, unique=False)
def __unicode__(self):
return self.user.username
UserProfile model:
class UserProfile(models.Model) :
user = models.ForeignKey(User, unique=True)
def get_favorites(self):
if self.user:
return self.user.favorite_set.all()
In my post_list view I pass all Posts to my template, and in the template I have a for loop that displays all Posts.
{% for post in post_list %}
<hr/>
<div id=”post_{{ post.id }}”>
{% include 'posts/_post.html' %}
</div>
{% endfor %}
Now in that for loop I would like to put a logic that will display "Favorited!" if the logged-in User has favorited the Post. I think the conventional SQL is something like this:
SELECT favorite.post FROM favorite WHERE favorite.user = user.id
So that in the template loop I can do
{% if post in the.above.SQL.query%}Favorited!{% endif %}
Now I just can't translate that to Django lingo for some reason. Your help is much appreciated!
The thing to recognise is that your Favorite model is actually the through table of a many-to-many relationship between Post and User. Django can actually manage that automatically if you declare a ManyToManyField somewhere. Personally, I would do that on UserProfile - so the relationship actually becomes one between Post and UserProfile:
class UserProfile(models.Model):
favorites = models.ManyToManyField(Post, related_name='favorited_by')
Now you don't need your get_favorites method, as it is available via userprofile.favorites.all(). You could just use this as-is in the template:
{% if post in userprofile.favorites.all %}Favorited!{% endif %}
but this will end up being extremely inefficient, as you'll be doing the same identical query for each post in your list of posts. So, use the {% with %} tag to get the favorites once before the loop:
{% with userprofile.favorites.all as favorite_posts %}
{% for post in post_list %}
{% if post in favorite_posts %}Favorited{% endif %}
...
{% endfor %}
{% endwith %}
While Daniel makes good point, i'll just post the query you wanted :)
Post.objects.filter(favorite__user=user)
Since its many to many relationships,
fav_post = user.favourite.all() you can pass this fav_post to context. Then in the template, you will need to iterate that context key
Related
A newbie in the world of Django. I have what seems to be a general problem but I couldn't find a good answer on the Internet.I need to pass a django queryset to template to display a list. Of those Article objects, some may have been written by the user, I want to highlight/star those particular articles. What is the best practice/solution to achieve this?
for example:
class Article(models.Model) :
article_text = models.CharField(max=32)
written_by = models.CharField()
So I can access the list of all articles in the views.py:
article_list = Articles.objects.all()
And I can filter all the articles by my current logged in user as
my_article = article_list.filter(written_by=current_user)
Within Template I want to display a list of all articles, but 'star' only the ones which have been written by the current logged in user
so in my template I want to do something like this:
{% for article in article_list %}
{% if article.some_flag %}
Starred Article
{% endif %}
{% endfor %}
Question: Is there a good way to annotate 'article_list' objects with a flag some_flag that marks 'my_articles' in views.py?
Or is there a way to do this within template by passing both article_list and mylist and doing the lookup inside the template code?
Something like (code for illustration only):
{% for article in article_list %}
{% if article.pk in mylist.keys %}
Starred Article {{ mylist.pk }}
{% endif %}
{% endfor %}
Any pointers would be very helpful. Hope the question is clear.
Firstly change your Article model to this:
from django.conf import settings
class Article(models.Model) :
article_text = models.CharField(max=32)
written_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Next in your template check if user is same as the request's user:
{% for article in article_list %}
{% if article.written_by == request.user %}
Starred Article
{% endif %}
{% endfor %}
Also it looks like you have some current_user (don't know what this variable is, perhaps the users username?) which you are using to match the users, if you really don't want to change your Model you can pass that into the context and write {% if article.written_by == current_user %}. But I would recommend to change the Article model for further ease while developing.
I'm creating a site and I successfully added an email confirmation system using django-allauth. Now I would like to have some parts of my site available only to users who confirmed their email.
Suppose that part looks something like this:
{% extends "main/header.html" %}
{% if user.is_authenticated %}
{% block content %}
<body>
<div>
<p> Here are are a bunch of features etc... </p>
</div>
</body>
{% endblock %}
{% endif %}
Now, I know how to do that in theory, but not practically. I figured that I need to add a statement that checks if the email is confirmed. What I'm not understanding is where should I add this statement and what that should look like. Should it be on the template? Or should I create a view for this? Any advice is appreciated? Thanks in advance!
I think its best to put the login in your CustomUser Model:
class CustomUser(AbstractUser):
#property
def has_verified_email(self):
return self.emailaddress_set.filter(verified=True,primary=True).exists()
Then use in template:
{% if user.has_verified_email %}
// some lines
{% endif %}
If you haven't overridden your User model, then you can put it in a separate model which has a OneToOne relation to your User model:
class Profile(models.Model):
user = models.OneToOneField(User)
#property
def has_verified_email(self):
return self.user.emailaddress_set.filter(verified=True,primary=True).exists()
Then use it in template:
{% if user.profile.has_verified_email %}
// some lines
{% endif %}
Second best option would be to use in View, but you will need to put the same logic in every view. If you are using a Class Based View, you can make a Mixin and use it in them:
class SomeMixin(object):
def get_context_data(self, *args, **kwargs):
context = super(SomeMixin, self).get_context_data(*args, **kwargs)
context['has_verified_email'] = self.request.user.emailaddress_set.filter(verified=True,primary=True).exists()
return context
class ActualView(SomeMixin, TemplateView):
# subclassing from the mixin in
// template code
{% if has_verified_email %}
// some lines
{% endif %}
I am generating a generic list right now, with the following code:
views.py
class ServiceReportIndex(LoginRequiredMixin, ListView):
model = TblServiceRecords
context_object_name = 'all_servicereports'
login_url = 'login'
template_name = 'servicereport/servicereport_index.html'
def get_context_data(self, **kwargs):
context = super(ServiceReportIndex, self).get_context_data(**kwargs)
context['companies'] = TblCompanies.objects.all()
return context
In my template, I want to generate a URL using both of the models. The TblServiceRecords model contains a column that references the company_id, which is the primary key of the appropriate company in the TblCompanies model. I want to use the company_name from the Companies model in my list view. How would I go about doing that? I'm sure it's simple but I can't seem to get my url tags done correctly.
<div class="col-sm-4">
<p>Company Name</p>
{% for servicereport in all_servicereports %}
<p>{% for servicereport.company_id in companies.company_id %} {{ companies.company_name }} {% endfor %}</p>
{% endfor %}
</div>
Also, how can I be sure my views.py is set up correctly for multiple model functionality? I ask because if I put
{% for company_name in companies %}
{{companies.company_name}}
{% endfor %}
In my template, nothing comes up, but there are no errors either.
Probably you cannot see companies bacause of this:
{{companies.company_name}}
companies is queryset and it does not have company_name property.
Try this:
{% for company_name in companies %}
{{company_name.company_name}}
{% endfor %}
Since a few weeks I am learning Python and Django. Up to this point it has been enough to read the questions and the answers of other users.But now the moment of my first own question has come.
I will try to describe my problem as best i can. My problem is that I cant query or get the data I want.
I want to get the url of the first object of class Image which is associated by ForeignKey to a Gallery, which is associated by ForeignKey to the class Entry.
Here the models.py so far:
class BlogEntry(models.Model):
...
title = models.CharField(max_length=100)
...
class Gallery(models.Model):
entry = models.ForeignKey('BlogEntry')
class Image(models.Model):
gallery = models.ForeignKey('Gallery')
picture = models.ImageField(upload_to='img')
The View:
def view(request):
return render_to_response('mainview.html', {
'entryquery': BlogEntry.objects.all(),
}
)
The Template:
{% for item in entryquery %}
<h1>{{ item.title }}</h1>
<img src="{{ item.WHAT TO ENTER HERE? :) }}" />
{% endfor %}
It is clear what I want?
Could somebody help me and when possible write a short explanation?
greetings
Bastian
You can access related members just like other attributes in a template, so you can do something like: item.gallery_set.all.0.image_set.all.0.picture.img. However, it might be easier to define a method on BlogEntry that looked up and returned the appropriate picture, so that you could just do item.first_image or something like that
class BlogEntry(models.Model):
...
title = models.CharField(max_length=100)
...
class Gallery(models.Model):
entry = models.ForeignKey('BlogEntry',related_name="galleries")
class Image(models.Model):
gallery = models.ForeignKey('Gallery',related_name='images')
picture = models.ImageField(upload_to='img')
You have to add related_name in foreign key in gallery model and in template view:
{% for g in blogentry.galleries.all %}
{{g.name}}
{%for i in g.images.all %}
<img src="{{i.picture.url}}">{{i.picture}}</img>
{% endfor %}
{% endfor %}
Hay, is it possible to a get a request.session value from a model method in django?
MEGA UPDATE
Here is my model
class GameDiscussion(models.Model):
game = models.ForeignKey(Game)
message = models.TextField()
reply_to = models.ForeignKey('self', related_name='replies', null=True, blank=True)
created_on = models.DateTimeField(blank=True, auto_now_add=True)
userUpVotes = models.ManyToManyField(User, blank=True, related_name='threadUpVotes')
userDownVotes = models.ManyToManyField(User, blank=True, related_name='threadDownVotes')
votes = models.IntegerField()
def html(self):
DiscussionTemplate = loader.get_template("inclusions/discussionTemplate")
return DiscussionTemplate.render(Context({
'discussion': self,
'replies': [reply.html() for reply in self.replies.all().order_by('-votes')]
}))
def _find_users_who_have_voted(self):
user_list = []
for user in self.userDownVotes.all():
user_list.append(user.id)
for user in self.userUpVotes.all():
user_list.append(user.id)
return user_list
users_voted = property(_find_users_who_have_voted)
and my view is called like this
<ul>
{% for discussion in discussions %}
{{ discussion.html }}
{% endfor %}
</ul>
and the template
<li>
<small>
({{ discussion.votes }} votes)
{% if user_id not in discussion.users_voted %}
user not in list!
{% endif %}
</small>
<strong>{{ discussion.message }}</strong>
{% if replies %}
<ul>
{% for reply in replies %}
{{ reply }}
{% endfor %}
</ul>
{% endif %}
the value 'user_voted' returns a list of user ids who has voted on this discussion.
I want to see if the request.session['user'].id value is inside this list
Why don't you use Django's render_to_string inside a view, which would have request happily available to it, and avoid model method altogether?
UPDATE: after skimming your mega update, you should look into Django's inclusion tags and use the data from the model to fill a template, not use a model to render the template. Keep your model and your template separate - Django is an MVT / MCV framework for good reason :)
you can access the current user, and so their session using threadlocals middleware
http://code.arcs.org.au/gitorious/django/django-andsome/blobs/ee8447e3dad2da9383ff701ec640b44cd50d2b0a/middleware/threadlocals.py
but keep in mind:
http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser
There might be better solutions to your problem. Maybe you'd like to elaborate why you need request.session on model level?
UPDATE:
since you explicitly call some method - probably from a view - why don't you just put the request.user as parameter to your html method?
models.py:
def html(self, user):
your code...
views.py:
yourmodel.html(request.user)
UPDATE to your MEGA UPDATE:
This is exactly what {% include %} is for:
in your first template do this:
{% for discussion in discussions %}
{% include "discussion.html" }}
{% endfor %}
and the second template has request.user.id in its namespace:
{% if request.session.user.id not in discussion.users_voted %}
user not in list!
{% endif %}