How to get model-objects using other models in django - django

I need if user requests to get the following page the response of the request would be the page containing specific posts made by the users who is followed by the user who requests.
I thought to do some actions to do this:
Get the requester
Get the users who are followed by the requester
Get the posts created by the users the who are being followed
In my models.py:
class User(AbstractUser):
image_url = models.CharField(max_length=5000, null=True)
class Follow(models.Model):
follower = models.ForeignKey(
User, on_delete=models.PROTECT, related_name="follower")
following = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='following')
class Post(models.Model):
content = models.CharField(max_length=140)
date_created = models.DateTimeField(auto_now_add=True)
poster = models.ForeignKey(User, on_delete=models.CASCADE)
In my views.py:
def following_page(request, username):
user = User.objects.get(username=username)
f = user.following.all()
posts = Post.objects.filter(poster=f.following)
posts = posts.order_by("-date_created").all()
return render(request, 'network/index.html', {
"posts": posts
})
It says
AttributeError 'QuerySet' object has no attribute 'following'
Should I have to change the model? How to solve the problem?

You can filter with:
from django.contrib.auth.decorators import login_required
#login_required
def following_page(request):
posts = Post.objects.filter(poster__following__follower=request.user)
return render(request, 'network/index.html', {
'posts': posts
})
Since you use the logged in user, one uses request.user, and thus it makes no sense for the view to accept a username.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related

How to query User model by 'custom' fields? (django.db.models.fields.related_descriptors.ReverseOneToOneDescriptor)

I extended the User model using my account app.
Model Account app:
from django.db import models
from django.contrib.auth.models import User
from departments.models import Department
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', blank=True)
department = models.ForeignKey(
Department, on_delete=models.SET_NULL, null=True, related_name='department')
def __str__(self):
return self.user.username
Now I need to send the count of users from the same department to my template...
View:
from django.contrib.auth.models import User
#login_required
def home(request):
context = {
'title': 'Dashboard',
'department_members': 'department_members': User.objects.filter(department=request.user.account.department).count(),
}
return render(request, 'app/dashboard.html', context)\
department_members is always 1 even though I have more users on the same department.
I figure that the problem is that User don't have department field by default, so I can't say User.account.objects.filter(department=request.user.account.department)
I've tried a lot of queries and looked into django docs but I could't find the proper manner on how to retrieve this info.
Anyone have the same problem? Any tips on how I can debug/create my query in a better way?
Thanks to all in advance!
Maybe changing department_members queryset to:
context = {
'title': 'Dashboard',
'department_members': Account.objects.filter(department=request.user.account.department).count() if hasattr(request.user, "account") else 0,
}
Solves your problem.

Django ValueError: Cannot use QuerySet for "": Use a QuerySet for "User"

I'm working on a project in CS50w where I have to show the posts of the user I'm following and I'm getting the following error
ValueError: Cannot use QuerySet for "Following": Use a QuerySet for "User".
models.py:
class Post(models.Model):
"""Tracks all the posts"""
text = models.TextField(max_length=256)
user = models.ForeignKey(User, on_delete=models.CASCADE)
date_posted = models.DateTimeField(auto_now_add=True)
class Following(models.Model):
"""Tracks the following of a user"""
user = models.ForeignKey(User, on_delete=models.CASCADE)
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name="followers")
And this how I'm trying to retrieve the posts of the users I'm following:
views.py
# Gets all the posts from the users the current user is following
followings_usernames = Following.objects.filter(user=request.user)
posts = Post.objects.filter(user=followings_usernames)
Any help is appreciated.
You can filter based on a field (Following.user) through a reverse relation (followers) through the Post.user field:
posts = Post.objects.filter(user__followers__user=request.user)
See the Django documentation for lookups that span relationships and the usage of double underscores to separate models and fields.
Try using this, it might help
# Gets all the posts from the users the current user is following
followings_usernames = list(Following.objects.filter(user=request.user).values_list('user', flat=True))
posts = Post.objects.filter(user__in=followings_usernames)

Trying to pass a foreign key of my model into URL for dynamic routing

I have 3 models, a custom user model (using AbstractUser - User/Brand models) and a Message model:
class User(AbstractUser):
is_brand = models.BooleanField(default=False)
is_influencer = models.BooleanField(default=False)
class Brand(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name="brand_info")
email = models.EmailField()
brand_name = models.CharField(max_length=100, blank=True)
class Message(models.Model):
recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='recipient')
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sender')
message_content = models.TextField()
send_time = models.DateTimeField(auto_now_add=True)
I have a view where I want to load up all the messages associated with a particular Brand, and this page will also have the attribute (from Brand model) as a dynamic URL parameter.
Here's my current code for views.py:
def conversation_view(request, username):
messages = Message.objects.filter(Q(message__sender=username) | Q(message__recipient=username)).order_by('send_time')
return render(request, "conversation.html", {
'messages': messages
})
And here's my urls.py:
urlpatterns = [
path('conversation/<username>/', views.conversation_view, name='conversation_view')
]
When I try and load up a page with the appropriate conversation/ URL, I get the following error message: invalid literal for int() with base 10: 'username'
I'm not sure why Django is expecting an int() here? Is it because I'm using sender/recipient from Message model in my view, which are both foreign keys?
You filter on the message__sender, so then it is expecting a User object, or the primary key of a User object.
You can however filter with message__sender__username=username, the same applies for the recepient:
def conversation_view(request, username):
messages = Message.objects.filter(
Q(message__sender__username=username) |
Q(message__recipient__username=username)
).order_by('send_time')
return render(request, "conversation.html", {
'messages': messages
})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Filter the parent model instances based on an attribute of the associated model in Django

I am trying to get the Users of a particular city in the userprofile model. My code is as below:
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=250, default='Bengaluru', blank=False, null=False)
views.py
def home(request):
users = User.objects.filter(is_staff=False).prefetch_related(
Prefetch('userprofile',
queryset = UserProfile.objects.filter(city='Mumbai')
)
)
context = { 'users': users }
return render(request, 'users/home.html', context)
But in the above code, users object contains all the users but the userprofiles only where the city is Mumbai. What I want is do get only the users whose userprofile city is Mumbai. Not all the users. How can I do that? What am I doing wrong here?
I found the answer to my problem:
users = User.objects.filter(
is_staff=False,
userprofile__city='Mumbai'
).prefetch_related(
Prefetch('userprofile',
queryset = UserProfile.objects.filter(city='Mumbai')
)
)
If there is any other better way then please post your answer.

Connect one model to another

I'm trying to make a simple shop for myself without popular modules. And stack on next things.
I have two models - articles (kind of "product" in here) and user with custom profile model. So what I need is when User goes to Article page, he can push the button ("Buy" maybe) and that article model connects to User. So he can see it on his profile page. Also, I need a check function in template, indicates that User bought Article or not (some kind "if-else").
I'm already hooked up my Article model to my User Profile model with ForeignKey, but right now I don't know where the next point to move. Can someone help?
My model userprofile:
import PIL
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
from django.db import models
from article.models import Article
class UserProfile(models.Model):
user = models.OneToOneField(User)
user_picture = models.ImageField(upload_to='users', blank=False, null=False, default='users/big-avatar.jpg')
user_balance = models.IntegerField(default=0)
user_articles = models.ForeignKey(Article, blank=True, null=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u) [0])
My forms.py for userprofile
from django import forms
from userprofile.models import User
from userprofile.models import UserProfile
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('email', 'first_name', 'last_name',)
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('user_picture', 'user_balance')
My view for userprofile
from django.shortcuts import render, render_to_response, redirect
from django.shortcuts import HttpResponseRedirect, Http404, HttpResponse
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.core.context_processors import csrf
from userprofile.forms import User
from userprofile.forms import UserForm
from userprofile.forms import UserProfileForm
def userprofile(request, username):
u = User.objects.get(username=username)
if request.POST:
user_form = UserForm(request.POST, instance=request.user)
user_profile = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
if user_form.is_valid() and user_profile.is_valid():
user_form.save()
user_profile.save()
else:
user_form = UserForm(instance=request.user,
initial={
'first_name': request.user.first_name,
'last_name': request.user.last_name,
'email': request.user.email,
})
user = request.user
profile = user.profile
user_profile = UserProfileForm(instance=profile)
return render_to_response('profile.html', {'user_form': user_form, 'user_profile': user_profile}, context_instance=RequestContext(request))
And my model article, that needs to be hooked up:
import PIL
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
from django.db import models
class Article(models.Model):
class Meta():
db_table = 'article'
article_title = models.CharField(max_length=200, blank=False, null=False)
article_anchor = models.CharField(max_length=200, blank=False, null=False)
article_image = models.ImageField(upload_to='items', blank=False, null=False)
article_users = models.IntegerField(default=0)
class Comments(models.Model):
class Meta():
db_table = 'comments'
comments_date = models.DateTimeField()
comments_text = models.TextField(verbose_name=u'')
comments_article = models.ForeignKey(Article)
comments_from = models.ForeignKey(User)
Just to clarify a few things:
I assume a user can purchase multiple articles
An article can belong to many users
If this is the case, then you have a many-to-many relationship between the user model and the article model. So what you can do is to modify your Article model:
class Article(models.Model):
class Meta():
db_table = 'article'
article_title = models.CharField(max_length=200, blank=False, null=False)
article_anchor = models.CharField(max_length=200, blank=False, null=False)
article_image = models.ImageField(upload_to='items', blank=False, null=False)
article_users = models.ManyToManyField(User) # <- use ManyToManyField instead of IntegerField
Another approach is to create a OrderHistory model to store who (User) purchased what(Article):
class OrderHistory(models.Model):
user = models.ForeignKey(User)
article = models.ForeignKey(Article)
purchase_date = models.DateTimeField(auto_now_add=True)
Let's assume that you used the first approach. Modifying models is not enough. There are a few things you need to add to your site:
A webpage for displaying a list of Articles for users to purchase
So you need a template file that shows a list of avaiable articles
you need a view function to render this page
this page will contain a list of articles and a way for users to select which article they want to buy via checkbox (or many buy buttons beside each article, your choice). So bascially your template will have a element that contains a list of articles and a 'buy' button to POST this data back to server
When a user clicks on the 'Buy' button, the data is submitted to a url that you need to define in the urls.py
add a new url in your urls.py and hook it to a view function
the view function will use request.user to identify which user it is and use the data in request.POST to figure out the article ids that's being purchased.
then you need to find the article from the database using
article = Article.objects.filter(pk=the_id_you_received_from_POST)
article.article_users.add(request.user)
article.save()
return a success message
Read this link before you start:
https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/
EDIT:
As Daniel pointed out, remove the following line from UserProfile
user_articles = models.ForeignKey(Article, blank=True, null=True)
You have to think about if the relationship between a user and an article is one-to-many or many-to-many. models.ForeignKey means one user can buy many articles, but once an article has been purchased, it can only belong to one user.(which is probably not what you want)
To pass data from a webpage to your view function, there are two ways:
Through GET request: parameters are appended to the end of the url, here is a good example of how it is done in Django: Capturing url parameters in request.GET
Through POST request: usually, you would have a form on the page and a submit button to submit the data to a predefined URL:
<form action = "url_for_handling_POST_request" method = "post">
Please follow Django's tutorial:
- https://docs.djangoproject.com/en/1.8/intro/tutorial04/
- https://docs.djangoproject.com/en/1.8/topics/forms/#processing-the-data-from-a-form
In your case, you should use POST request. so read the documentation above. It contains an example that matches to what you need.
Note: don't forget to insert the CSRF token inside your form or Django will complain:
<form ...>
{% csrf_token %}
</form>