I have a Django project where a user can re post other users posts by creating a relationship between the user and the post itself. But when I display this on my template, I want the tweets that have been re posted to have a different link next to them in order to un repost but instead with my current set up it still has the re post link, so I was just wondering how I could see if a relationship exists in a Django template as part of my conditional.
template
{% for tweets in combined_tweets %}
<p>{{ tweets.userprofile.user}} | {{ tweets }} | {{ tweets.date }} |
{% if tweets.userprofile.user == request.user %}
<a href='{% url "delete_tweet" request.user.id tweets.id %}'>DELETE</a>
{% elif ###Something to check if realtionship exists### %}
UN REPOST LINK
{% else %}
<a href='{% url "retweet" tweets.id %}'>RETWEET</a>
{% endif %}</p>
{% endfor %}
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.CharField(max_length=120, blank=True, verbose_name='Biography')
follows = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True)
theme = models.ImageField(upload_to=get_image_path, blank=True)
profile_picture = models.ImageField(upload_to=get_image_path, blank=True)
def __str__(self):
return self.bio
class Tweet(models.Model):
userprofile = models.ForeignKey(UserProfile)
retweet = models.ManyToManyField(UserProfile, related_name='retweet_people', symmetrical=False, blank=True)
tweets = models.TextField(max_length=120)
date = models.DateTimeField()
You can check that a relationship exists between the current user and other user tweets using a custom template filter.
We will write a custom template filter check_relationship_exists which will take the current user as the argument. This will check if the current tweet object is related to the user passed by performing a filter on its retweet attribute using user.id. If there exists a relationship, then the UN REPOST link will be displayed otherwise a RETWEET link will be shown.
from django import template
register = template.Library()
#register.filter(name='check_relationship_exists')
def check_relationship_exists(tweet_object, user):
user_id = int(user.id) # get the user id
return tweet_object.retweet.filter(id=user_id).exists() # check if relationship exists
Then in your template, you can do the following:
{% elif tweets|check_relationship_exists:request.user %}
Related
I need to find services with pricing for each user. I've defined my models:
class User(AbstractUser):
"""Default user model."""
username = None
email = models.EmailField(unique=True)
proposals = models.ManyToManyField(
Service,
through=Pricing,
blank=True)
class Service(models.Model):
name = models.CharField(max_length=50)
class Pricing(models.Model):
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
service = models.ForeignKey(Service, on_delete=models.PROTECT)
price = models.IntegerField()
In my template, I can get my user with associated proposal with this for loop
{% for proposal in object.proposals.all %}
{{ proposal }}
{% endfor %}
I do not have prices but only services names. What am i missing ?
Sets the related_name of the foreign key field:
class Pricing(models.Model):
user = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='pricing_instances') # Replace 'pricing_instances' with what makes sense to you
service = models.ForeignKey(Service, on_delete=models.PROTECT)
price = models.IntegerField()
Then you can access price like this:
{% for pricing_instance in object.pricing_instances.all %}
{{ pricing_instance.price }}
{% endfor %}
You enumerate over the object.pricing_set.all() with:
{% for pricing in object.pricing_set.all %}
{{ pricing.service }}: {{ pricing.price }}
{% endfor %}
This will however result in an N+1 problem, by making use of a Prefetch object in the view, we can avoid that.
If you are for example fetching a User object, you can prefetch the pricings and the related services with:
User.objects.prefetch_related(
Prefetch('pricing_set', Pricing.objects.select_related('service'))
)
If you thus make use of a single User with primary key pk, then this can be implemeted as:
object = User.objects.prefetch_related(
Prefetch('pricing_set', Pricing.objects.select_related('service'))
).get(pk=some_pk)
models.py
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE)
active = models.BooleanField(default=True)
...
class Review(models.Model):
paper = models.ForeignKey(Book, null=True, on_delete=models.CASCADE, related_name='book_class_related_name')
user = models.ForeignKey(User, on_delete=models.CASCADE)
comment = RichTextField()
status = models.CharField(max_length=10, choices=options, default='draft')
...
class TrackReviewRequests(models.Model):
paperid = models.ForeignKey(Book, null=True, on_delete=models.CASCADE, related_name='book_track')
numberOfTimesReviewRequestSent = models.PositiveSmallIntegerField(default=0)
...
views.py
reviews_in_draft = Review.objects.filter(paper__active=True).filter(status='draft')
return render(request,
'accounts/profile.html',
{
'reviews_in_draft': reviews_in_draft,
})
profile.html
Here I tried accessing the 'numberOfTimesReviewRequestSent' using the following code:
{% for review in reviews_in_draft %}
{{ review.paper.book_track.numberOfTimesReviewRequestSent }}
{% endfor %}
But I am getting empty string.
Then I wrote a method inside the Book model
def get_TrackReviewRequests_numberOfTimesReviewRequestSent(self):
return self.book_track.numberOfTimesReviewRequestSent
and tried accessing the numberOfTimesReviewRequestSent in the profile.html using the following code:
{{ review.paper.get_TrackReviewRequests_numberOfTimesReviewRequestSent }}
But this time I got the error stating
'RelatedManager' object has no attribute 'numberOfTimesReviewRequestSent'
Ultimately, I want to access the numberOfTimesReviewRequestSent in the template using the context variable.
A Bookcan have multiple TrackReviewRequests (Since TrackReviewRequests has a foreign key to Book, if in reality there can only be one then you should use a OneToOneField [Django docs] instead) hence review.paper.book_track is not an instance of TrackReviewRequests but as the error says a RelatedManager.
Hence when you write review.paper.book_track.numberOfTimesReviewRequestSent it doesn't make much sense. You can instead loop over the related instances if you want in the template like so:
{% for review in reviews_in_draft %}
{% for review_request in review.paper.book_track.all %}
{{ review_request.numberOfTimesReviewRequestSent }}
{% endfor %}
{% endfor %}
how can I access to first_name of a user in django template?. for example my writer in django model is like this below :
writer = models.ForeignKey(User, on_delete=models.CASCADE)
If User is the Django default user model, it's simply
writer.first_name
-- e.g. if your example is in a post model you're rendering,
{{ post.writer.first_name }}
in a template.
I have somewhat of a similar setup and this works for me:
models.py
class Customers(models.Model):
name = models.CharField(("Customer name"), max_length=200)
class Licenses(models.Model):
customer = models.ForeignKey(Customers, on_delete=models.CASCADE)
views.py
def licenses (request):
lic = Licenses.objects.all()
return render(request, 'licenses.html',{'lic': lic})
licenses.html
{% for license in lic %}
{{ license.customer.name }}
{% endfor %}
Apologies for the unclear title, I'm not sure how to articulate my question in a few words.
Basically, within my view I have a variable containing a list of objects (photos):
photos = Photo.objects.all()
In my template I have a for loop for these objects where I display the attributes (e.g. photo.author ). I would like to have some logic to be run on individual photo instances:
all_likes = Like.objects.all()
for photo in photos:
pic_likes = all_likes.filter(photo_id=id)
like_count = len(pic_likes)
liker = pic_likes.filter(liker_id=request.user.id)
if len(liker) != 0:
liked=True
but using a for loop inside the view causes the error
int() argument must be a string, a bytes-like object or a number, not 'builtin_function_or_method'
How should I go about having logic for the photo instances but not the object list as a whole?
My Photo model is as follows:
class Photo(models.Model):
image = models.ImageField(upload_to='uploaded_images', blank=True)
title = models.CharField(max_length=128)
author = models.ForeignKey(settings.AUTH_USER_MODEL, default = 1)
slug = models.SlugField()
likes = models.ManyToManyField(User, related_name='likes')
description = models.CharField(max_length=1000, blank=True)
and my like model is:
class Like(models.Model):
liker = models.ForeignKey(User, related_name='liker')
photo = models.ForeignKey(Photo, related_name='photo')
liked = models.BooleanField()
I suggest you change the related_name attributes in you Like model, maybe even remove it to use the default names:
class Like(models.Model):
liker = models.ForeignKey(User)
photo = models.ForeignKey(Photo)
liked = models.BooleanField()
Now you can use it like this:
all_likes_of_a_user = user_instance.like_set.all()
all_likes_of_a_photo = photo_instance.like_set.all()
Now, to iterate over the photos in the view, you can use:
for photo in Photo.objects.all():
like_count = photo.like_set.count()
has_liked = photo.like_set.filter(liker=request.user).exists()
And for using that in your templates, you could add a nested loop:
{% for photo in Photo.objects.all %}
Like count: {{ photo.like_set.count }}
Has this user liked this photo:
{% for like in photo.like_set.all %}
{% if like.liker == user %}
yes
{% endif %}
{% endfor %}
{% endfor %}
Or add a method to your Photo model:
class Photo(models.Model):
...
def users_that_liked_it(self):
return [
e.liker.pk
for e in self.like_set.all()]
{% for photo in Photo.objects.all %}
Like count: {{ photo.like_set.count }}
Has this user liked this photo:
{% if user.pk in photo.users_that_liked_it %}
yes
{% else %}
no
{% endif %}
{% endfor %}
I have two models that I am working with. First one is a education model in which one user can enter multiple educational qualifications instances:
class Education(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
degree_name = models.CharField(max_length=150,null=True,blank=True)
institute_name = models.CharField(max_length=150, null=True, blank=True)
date_start = models.CharField(null=True,blank=True,max_length=25)
date_end = models.CharField(null=True,blank=True,max_length=25)
description = models.TextField(null=True,blank=True,max_length=1000)
Second Model is the 'User info' model in which one user can have maximum one instance:
class Userinfo(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
user_info = models.ForeignKey(User_info,related_name='user_info',on_delete=models.CASCADE,null=True)
profile_pic = models.FileField(null=True,blank=True)
dob = models.CharField(max_length=25,null=True,blank=True)
nationality = models.CharField(max_length=100, null=True, blank=True)
headline = models.CharField(max_length=160, null=True,blank=True)
summary = models.TextField(max_length=1000, null=True, blank=True)
current_salary = models.FloatField(null=True,blank=True)
japanese_level = models.CharField(max_length=50, null=True, blank=True)
english_level = models.CharField(max_length=50, null=True, blank=True)
career_level = models.CharField(max_length=50,null=True,blank=True)
availability = models.CharField(max_length=50, null=True, blank=True)
expected_salary = models.FloatField(null=True, blank=True)
job_role = models.CharField(max_length=50,null=True)
When I use any query to get any instance of 'User info' like:
Userinfo.objects.filter(user=request.user)
How can i related both models so that when looping through Userinfo, I should be able to get multiple instances of it in Education model. How should I change my models and query them ?
I see that you already have a foreign key to the User model inside your Education model. There is no need for a foreign key in the UserInfo Model. You can fetch all the Education instances for a given user just by making an extra call:
Education.objects.filter(user=request.user)
or you can change request.user to the actual user that you need to get.
EDIT:
without making any changes to your code, you can get the multiple instances in the following way:
example views.py
def myView(request):
user_info = Userinfo.objects.get(user=request.user) #using get since only 1 instance always
educations = Education.objects.filter(user=request.user) #fetching all the instances for the education
context_dict = {"user_info": user_info}
educations_list = []
for e in educations:
educations_list.append(e)
# do whatever you need with the educations
# you can access user_info fields just by `user_info.field_name`
# and you can access the current education fields by `e.field_name`
context_dict["educations"] = educations_list
return render(request, "template.html", context_dict)
example usage in template.html
{% if user_info %}
<p>{{ user_info.field_name }}</p>
{% if educations %}
{% for e in educations %}
<div>{{ e.field_name }}</div>
{% endfor %}
{% endif %}
{% endif %}
EDIT 2 (including multiple userinfo instances)
views.py
def myView(request):
user_infos = Userinfo.objects.filter() # fetch all instances
context_dict = {}
result = []
for u in user_infos:
temp = []
educations_list = []
educations = Education.objects.filter(user=u.user) # fetch educations for the currently iterated user from user_infos
for e in educations:
educations_list.append(e)
temp.append(u) # append the current user_info
temp.append(educations_list) # append the corresponding educations
result.append(temp)
context_dict["result"] = result
return render(request, "template.html", context)
template.html
{% if result %}
{% for r in result %}
<div>{{ r.0 }}</div> <!-- r.0 is your currently iterated user_info can be used like: r.0.profile_pic for example -->
{% if r.1 %}
{% for e in r.1 %}
<div>e.degree_name</div> <!-- e is the current education on the current user_info -->
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
the code in the views.py is not perfect and might be worth to refactor a bit (how to build the final dictionary), but i believe this will give you an idea of how to do it.
Hope this helps!
ui = Userinfo.objects.filter(user=request.user)
this query will give you all the instances of Userinfo for request.user. you can access the value of Education attributes with looping like this:
for u in ui:
ui.education.degree_name
# and so on for other fields.
I think maybe your UserInfo model can have a OneToOne relationsship with user and then do something like
UserInfo.objects.filter(user=request.user).education_set.all()
Hope this helps.
Good luck!