Django, revover a model with multi foreign key - python

I would like to show all favorites of connected user.
Each user can add his own favorites. I created a model to manage this action.
In this one, I have two foreign key. One for the user and the second for the "favorite".
models.py
class Favorite(models.Model):
user = models.ForeignKey(User)
drud = models.ForeignKey(Drud)
def __unicode__(self):
return self.drud.secure_key
On my view, I want to show all favorite Drud of connected user. I tried to do something like that:
views.py
favorite = Favorite.objects.filter(drud=[d.secure_key for d in Drud.objects.filter(user=request.user)])
But, that does work...

You can do:
fav_druds = request.user.favorite_set.values_list('drud', flat=True)
In the template you can do:
{% for drud in fav_druds %}
{{drud.id}}: {{drud.secure_key}}
{% endfor %}
Edit:
favs = request.user.favorite_set.all()
{% for fav in favs %}
{{fav.drud.id}}: {{fav.drud.secure_key}}
{% endfor %}

Related

Show all comments from a specific user in django

I am trying to consolidate all the comments, on various products, from the logged in user in an "Account" page.
My initial plan was to request all comments from the user id.
Because I created a Profile model, I thought the right way to approach this was to link it to the profile id, and not directly to the use id.
Obviously, it's not working.
Am I close to it? or should I think of it completely differently? (new to programming, as you can see on the code)
Starting with my models.py
class ReviewRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="comments", on_delete=models.CASCADE)
review=models.TextField(max_length=250)
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
class Profile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
general_reviews = models.ForeignKey(ReviewRating,null=True, on_delete=models.CASCADE)
def str(self):
return str(self.user)
Views.py
def account(response, profile_id):
generalreviews_list = Profile.general_reviews.objects.all(pk=profile_id)
return render(response,"main/account.html", {'generalreviews_list':generalreviews_list})
URLS
path("account/<profile_id>/", views.account, name="account"),
Method - 1 (easiest and logical method)
profile.html:
{% for comment in request.user.reviewrating_set.all %}
{{ comment.review }}
{% endfor %}
Method - 2 (by setting a related_name what Django already defines one called foo_set )
You need to add a related_name attribute to the user field under ReviewRating
class ReviewRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE, related_name="comments")
That's It! You can use it on the profile HTML like this:
profile.html:
{% for comment in request.user.comments %}
{{ comment.review }}
{% endfor %}
The best way is to link it with the main user model in your case it will be best to link it with user_id. After that, you can use the following query to access all the comments made by the currently logged-in user.
Views.py
current_user = request.user
queryset_obj = Model.objects.filter(foreign_key_field_name=current_user)
context = {
'comments' = quesyset_obj,
}
Templates.py
{% for comment in comments %}
{{comment.review}}
{% endfor %}

Placing items below category in template

So I wrote a small shopping list application using Django. Users may enter their desired items which are stored in a database alongside a category they reside in to make the list presented to the user more clean and giving them (the users) a good overview of what they are going to buy.
The goal is to show the user a list which is categorized, something like this:
VEGETABLES
Paprika
Tomatoes
VARIOUS
Toothpaste
Toilet Paper
And so on. I have like five categories saved in my database and users may choose one corresponding category once they add an item to the list below which the item will be displayed in the list.
These are my database models:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=20)
tag = models.CharField(max_length=2)
def __str__(self):
return self.name
class Item(models.Model):
text = models.CharField(max_length=40)
count = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
complete = models.BooleanField(default=False)
def __str__(self):
return self.text
this is my views.py
def items(request):
item_list = Item.objects.order_by('id')
categories = Category.objects.all()
form = ItemForm()
context = {'item_list' : item_list, 'form' : form, 'categories' : categories}
return render(request, 'buyit/index.html', context)
and this is my index.html (very basic, stripped off all the css and html stuff):
{% for category in categories %}
<h4>{{ category.name }}</h4>
{% for item in category.item_set.all() %}
{{ item.text }}
{% endfor %}
{% endfor %}
I got this functions from the Jinja2 template from a code snippet and it might be, that I didn't understand it correctly.
However, the debugger tells me:
TemplateSyntaxError at /
Could not parse the remainder: '()' from 'category.item_set.all()'
Any hints on what I am doing wrong?
Simply displaying the categories worked fine but after adding
{% for item in category.item_set.all() %}
{{ item.text }}
{% endfor %}
things crashed.
Any help is highly appreciated!
Thanks in advance!
You can't use () in django templates. Just remove them to call the function / method.
From https://docs.djangoproject.com/en/3.1/ref/templates/language/#variables
Behind the scenes
Technically, when the template system encounters a dot, it tries the following lookups, in this order:
Dictionary lookup
Attribute or method lookup
Numeric index lookup
If the resulting value is callable, it is called with no arguments. The result of the call becomes the template value.
try this:
views.py:
def items(request):
commoditys = {category: Item.objects.filter(category=category) for category in Category.objects.all()}
form = ItemForm()
context = {'commoditys' : commoditys, 'form' : form}
return render(request, 'buyit/index.html', context)
index.html:
{% for category, commoditys in commoditys.items %}
<h3>{{ category.name }}</h3>
{% for commodity in commoditys %}
{{ commodity.text }}
{% endfor %}
{% endfor %}
Change the Category variable to a dictionary, where the Key of each item is the Category object, and its corresponding value is the item Queryset it belongs to

Django get user like from friend list

I'm a Django beginner, I have a friend field in Profile Model which list all my friend users. And also these friends liked my post. How do I get the names of only those users in my friends list to display in the post they liked.
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,... )
friends = models.ManyToManyField('Profile',related_name='my_friends')
class FriendRequest(models.Model):
to_user = models.ForeignKey(settings.AUTH_USER_MODEL,... )
from_user = models.ForeignKey(settings.AUTH_USER_MODEL,... )
class Post(models.Model):
poster_profile = models.ForeignKey(settings.AUTH_USER_MODEL,... )
likes = models.ManyToManyField(User, related_name='image_likes')
def home(request):
all_images = Post.objects.filter(poster_profile=request.user)
img = Post.objects.filter(likes__profile__friends__user=request.user)
{% if all_images %}
{% for post in all_images %}
#all_images code here
{{ post. likes.count }} #like count
{% for image in img %}<img src="{{ image.profile.profile_pic.url }}"> {% endfor %}#The profile_pic do not display
{% endfor %}
{% endif %}
if someone isn't your friend you can prevent him to like or even see (or comment) your post , or for each user who likes your post check if he is in your friend list then add him to a new emty list then render this list
Change your queryset in your view to this:
from django.db.models import Count, Q
all_images = Post.objects\
.filter(poster_profile=request.user)\
.annotate(likes_count=Count(
'likes',
distinct=True,
filter=Q(likes__profile__friends=request.user.profile))
then in your template each post has the annotation likes_count so you can do {{ post.likes_count }}.

Listing ForeignKey associated instances within template (queryset within a queryset)

I have a site which catalogs local hikes, and users can log that they have been on the hike. I have a search page which contains the hikes, and one of the fields I'm trying to display is a list of all the people who have been on the hike. I've got this figured out within the individual detail page of the hike, but can't figure out how to create a new queryset within the queryset which is printing the hikes, in order to display this info on a search page.
Here's some code:
models.py:
class Hike(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(unique=True)
...
class UserLog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
hike = models.ForeignKey(Hike, on_delete=models.CASCADE)
views.py:
def hike_list(request):
qs = Hike.objects.all()
... some other filters here
?-->users = UserLog.objects.filter(id=qs.id)
template:
{% for qs in qs %}
{{ hike.name }}{{ hike.other_details_and_stuff }}
?----> {% for users in hikes %}{{ user.name }}{% endfor %}
{% endfor %}
Here's the working code within the individual hike's detail page:
views.py:
def hike_detail (request, slug)
users = UserLog.objects.filter(hike__slug=slug)
How do I call on the slug from each individual item in the queryset, then run a queryset on that?
The easiest is to add a ManyToManyField to Hike:
class Hike(models.Model):
...
users = models.ManyToManyField(User, through='app.UserLog')
If you have no extra fields in UserLog, you can even remove the UserLog model and the through parameter alltogether. In the template you can do:
{% for hike in qs %}
{{ hike.name }}{{ hike.other_details_and_stuff }}
{% for user in hike.users.all %}{{ user.name }}{% endfor %}
{% endfor %}
In order avoid too many queries, you should prefetch the users in the Hike query in the view:
qs = Hike.objects.all().prefetch_related('users')
Without the ManyToManyField, you could add a property and user the same template, but the prefetch clause could not be used that easily:
class Hike(models.Model):
...
#property
def users(self):
return User.objects.filter(userlog__hike=self)

How to add variable number of ModelForms to Template?

I'm trying to create a page where I can create as much objects as User wants.
For simplicity, there is a simple model:
class Person(models.Model):
name = models.CharField(max_length=40)
surname = models.CharField(max_length=40)
There is a form:
class PersonCreationForm(forms.Form):
class Meta:
model = Person
fields = '__all__'
Now what I want is to allow user to create as much "persons" as they can. So at first, they can see only one or two PersonCreationForm's, but they can add another forms by themselves.
In fact, in my case, it could be limited (let's say max 20 forms)
Something like the + at the bottom:
I've already tried this desperate thing:
{% for i in "xxxx" %} # tried to create 4 forms...
{{ person_creation_form | crispy }}
{% endfor %}
I've read documentation about FormSets but it does not helped.
FormSets:
views.py:
from django.forms import formset_factory
PersonCreationFormSet = formset_factory(PersonCreationForm,extra=2,max_num=1)
def PersonCreationView(request):
formset = PersonCreationFormset()
return render(request,'person-creation.html',context={'formset':formset}
person-creation.html:
{{ formset }} # Tried both ways (commented too)
{# {% for x in formset %}#}
{# {{ x | crispy }}#}
{# {% endfor %}#}
No mather what is lower (extra or max_num), the lower number is the number of forms in html and I'm not able to call new forms)

Categories