Django filter foreignkey field - python

Short version:
I have a Django app used for recipes, and want to filter data to be sent to a template in my view. I basically want all recepies that are added by a specific user to be sent as context. The following filtering returns an error message invalid literal for int() with base 10: my_username.
recipes = Recipe.objects.filter(added_by = uname)
The variable uname is passed from a template. On the other hand, filtering on request.user works fine, but is not what I want.
recipes = Recipe.objects.filter(added_by = request.user)
Details:
My models are given (relevant fields) as:
class Recipe (models.Model):
...
...
added_by = models.ForeignKey(User)
Where User is an existing Django user. When I call {{ recipe.added_by }} in my template, I get the username as wanted. This username is passed on to a view with href="/profile/{{recipe.added_by}}", where the view looks like the following:
def profile(request, uname):
print uname #Correct username printed
print request.user #Logged in user (not relevant, as userprofile should be visible for all)
recipes = Recipe.objects.filter(added_by = uname) #Does not work. Why?
#recipes = Recipe.objects.filter(added_by = request.user)
form = CommentForm(request.POST)
context = {
'uname': uname,
'recipes': recipes,
'form': form,
}
return render(request, '*app_name*/profile.html', context)
Not sure what I am missing, but from what I can tell, it seems to have something to do with the fact that added_by has a Foreign Key to a User. I also tried to change the filter argument to recipe__added_by__added_by = uname according to [1], but Django then returned an error saying "Cannot resolve keyword 'recipe' into field", which seems obvious. My url is:
url(r'^profile/([a-zA-Z0-9]+)/$', 'profile', name='*app_name*-profile'),
Thanks for any reply. Sorry if this should have been obvious.
[1] Django models filter by foreignkey

You can try like:
recipes = Recipe.objects.filter(added_by__username = uname)
And request.user works fine for Recipe.objects.filter(added_by = request.user) because request.user is an object. details: https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships

When child class defined as
class Recipe (models.Model):
...
...
added_by = models.ForeignKey(User)
makemigration generates foreign key as added_by_id.
So, you have to use corresponding field name in filter.
Eg: recipes = Recipe.objects.filter(added_by_id = uname)

Related

ManyToMany Relationship between two models in Django

I am trying to build a website that users can add the courses they are taking. I want to know how should I add the ManyToMany relationship. Such that we can get all users in a course based on the course code or instructor or any field. And we can also get the courses user is enrolled in. Currently, my Database structure is:
class Course(models.Model):
course_code = models.CharField(max_length=20)
course_university = models.CharField(max_length=100)
course_instructor = models.CharField(max_length=100)
course_year = models.IntegerField(('year'), validators=[MinValueValidator(1984), max_value_current_year])
def __str__(self):
return self.course_code
and my user model:
class Profile(AbstractUser):
bio = models.TextField()
image = models.ImageField(default='defaults/user/default_u_i.png',
courses = models.ManyToManyField('home.Course',related_name='courses')
def __str__(self):
return self.username
I was wondering should ManyToMany relationship be in User model or the course model? Or will it make any difference at all?
EDIT: For adding course to post object now I am using this view but it seems to not work:
#login_required
def course_add(request):
if request.method == "POST":
form = CourseForm(request.POST or none)
if form.is_valid():
course = form.save()
request.user.add(course)
else:
form = CourseForm
context = {
'form':form
}
return render(request,'home/courses/course_add.html', context)
For a relational databases, the model where you define the ManyToManyField does not matter. Django will create an extra table with two ForeignKeys to the two models that are linked by the ManyToManyField.
The related managers that are added, etc. is all Django logic. Behind the curtains, it will query the table in the middle.
You however need to fix the related_name=… parameter [Django-doc]. The related_name specifies the name of the relation in reverse so from Course to Profile in this case. It thus should be something like 'profiles':
class Profile(AbstractUser):
bio = models.TextField()
image = models.ImageField(default='defaults/user/default_u_i.png',
courses = models.ManyToManyField('home.Course', related_name='profiles')
def __str__(self):
return self.username
You thus can obtain the people that particiate in a Course object with:
mycourse.profiles.all()
and you can access the courses in which a Profile is enrolled with:
myprofile.courses.all()
For more information, see the Many-to-many relationships section of the documentation.
You can add a course to the courses of a user with:
#login_required
def course_add(request):
if request.method == 'POST':
form = CourseForm(request.POST)
if form.is_valid():
course = form.save()
request.user.courses.add(course)
else:
form = CourseForm()
context = {
'form': form
}
return render(request,'home/courses/course_add.html', context)
You don't need to add the related name. Default is "courses_set" in your case.
Here is excerpt from: https://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects
Following relationships “backward” If a model has a ForeignKey,
instances of the foreign-key model will have access to a Manager that
returns all instances of the first model. By default, this Manager is
named FOO_set, where FOO is the source model name, lowercased. This
Manager returns QuerySets, which can be filtered and manipulated as
described in the “Retrieving objects” section above.

User Follower model on Django. Cannot use add() on a ManyToManyField which specifies an intermediary model. Use accounts.Contact's Manager instead

I am new to Django, Please forgive any silly mistakes in code or logic,
Intro: I am trying to create a user follower model in Django. Where users can follow and unfollow other users on the sites
Error: I have made the models for my follow/unfollow I have also made the views I am getting this error
AttributeError at /accounts/admin/follow/
Cannot use add() on a ManyToManyField which specifies an intermediary model. Use accounts.Contact's Manager instead.
The obj.followers.add(user) is highlighted in the traceback as the origin of the error
Below are my models.py
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=100)
country = models.CharField(max_length=100)
def get_absolute_url(self):
return reverse('accounts:profile', kwargs={'username': self.user.username})
class Contact(models.Model):
user_from = models.ForeignKey(User, related_name='suppporter')
user_to = models.ForeignKey(User, related_name='leader')
def __str__(self):
return '{} follows {}'.format(self.user_from, self.user_to)
User.add_to_class('following',
models.ManyToManyField('self', through=Contact, related_name='followers', symmetrical=False))
I think the models.py may be good. The fault I believe is in my views.
Below is my view.py
class FollowToggle(LoginRequiredMixin, RedirectView):
def get_redirect_url(self, *args, **kwargs):
username = self.kwargs.get('username')
print(username + " This is the user who will be followed") # This prints correct
profile = get_object_or_404(Profile, user__username=username)
print(profile) # This prints correct
obj = get_object_or_404(User, username=username)
print(obj) # This prints correct
url_ = profile.get_absolute_url()
print(url_) # This prints correct
user = self.request.user
print(user) # This prints correct
if user.is_authenticated():
if user in obj.followers.all(): # I know this is the source of the error.
obj.followers.remove(user)
else:
obj.followers.add(user)
return url_
Below are the Urls.py just in case
url(r'^(?P<username>[-\w]+)/follow/$', views.FollowToggle.as_view(), name='follow'),
You cannot use add and remove method for manytomany relation defined through third model. From the docs:
Unlike normal many-to-many fields, you can’t use add(), create(), or set() to create relationships
Instead you should use Contact manager:
if user.is_authenticated():
if user in obj.followers.all(): # I know this is the source of the error.
Contact.objects.filter(user_to=obj, user_from=user).delete()
else:
Contact.objects.create(user_to=obj, user_from=user)
In Django 2.2 you can use add, remove and set methods (Docs)
You can also use add(), create(), or set() to create relationships, as long as your specify through_defaults for any required fields

Cannot assign "<SimpleLazyObject: <User: XXX>>": "Comment.user" must be a "MyProfile" instance

Hello I know I have two problems here. one is a SimpleLazyObject issue which I can fix it in a kinda hackish way. The other is "Comment.user" must be a "MyProfile" instance which I don't know how to fix. I think somewhere in the way, things got mixed up.
def post(request, slug):
user = get_object_or_404(User,username__iexact=request.user)
try:
profile = MyProfile.objects.get(user_id=request.user.id)
# if it's a OneToOne field, you can do:
# profile = request.user.myprofile
except MyProfile.DoesNotExist:
profile = None
post = get_object_or_404(Post, slug=slug)
post.views += 1 # increment the number of views
post.save() # and save it
comments = post.comment_set.all()
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
post_instance = comment_form.save(commit=False)
post_instance.user = request.user #this is where error is occuring, if I put request.user.id simpleLazyObject dissapears.
post_instance.path = request.get_full_path()
post_instance.post = post
post_instance.save()
context_dict = {
'post' :post,
'profile' :profile,
'comments':comments,
'comment_form': comment_form
}
return render(request, 'main/post.html', context_dict)
I'm not sure what it means by Comment.user must be MyProfile instance.
In my comments app, models.py I have
class Comment(models.Model):
user = models.ForeignKey(MyProfile)
and in my accounts app, models.py I have
class MyProfile(UserenaBaseProfile):
user = models.OneToOneField(User, unique=True, verbose_name=_('user'), related_name='my_profile')
I'm not sure how to fix this problem, any help will be highly appreciated.
Comment has ForeignKey to MyProfile, yet in the line that triggers the error you provide a User model.
The correct way would be:
my_p = MyProfile.objects.get(user=request.user)
post_instance.user = my_p
Note that you use:
MyProfile.objects.get(user=request.user)
And not the id field. Although behind the scenes django does use the id field as the real foreign key in the database, in your code you use the object. A relational field is a descriptor where django does the magic to run a relational query.

Django Form: Default Value in one of the fields

This is my form:
class FriendRequestForm(forms.ModelForm):
class Meta:
model = Friend
my model:
class Friend(models.Model):
user1 = models.ForeignKey(User, related_name='frienduser1')
user2 = models.ForeignKey(User, related_name='frienduser2')
date = models.DateTimeField(auto_now=True)
accepted = models.BooleanField(default=False)
class Meta:
unique_together = ('user1', 'user2',)
In the template, how can I set user2 to be the ID based on who's profile page I am on? So if I am user1, and I am on user2's page (where this form loads in the html), I want user2 in the form to be set properly from the html template. Thanks!
You can't set anything in templates but assume that you actually meant corresponding view. If so, you can set initial value for the form easily:
def profile_view(request, user_id):
user = User.objects.get(id=user_id)
form = FriendRequestForm(initial={'user2': user})
I do not know which User model class you are using, but I'm assuming it is django's default User class. In that case, you can get the currently logged in user using request.user, and use that to populate the template field.
# views.py
def foo(request):
user = User.objects.get(id=request.user.id)
# TODO: check this is a valid user
render(
request,
'template.html',
{
# pass this user's id as a template variable
# or pass the entire user object itself
'user1_id': user.id,
})
# template.html
<div id='user1_field'>{{ user1_id }}</div>
IMHO, explicitly passing in required data is better than passing the entire request object in to the template like this:
from django.template import RequestContext
def foo(request):
return render_to_response(
'index.html', {'form': form, },
context_instance = RequestContext(request))

Foreign key to User table in django

I'm using django's built-in contrib.auth module and have setup a foreign key relationship to a User for when a 'post' is added:
class Post(models.Model):
owner = models.ForeignKey('User')
# ... etc.
Now when it comes to actually adding the Post, I'm not sure what to supply in the owner field before calling save(). I expected something like an id in user's session but I noticed User does not have a user_id or id attribute. What data is it that I should be pulling from the user's authenticated session to populate the owner field with? I've tried to see what's going on in the database table but not too clued up on the sqlite setup yet.
Thanks for any help...
You want to provide a "User" object. I.e. the same kind of thing you'd get from User.objects.get(pk=13).
If you're using the authentication components of Django, the user is also attached to the request object, and you can use it directly from within your view code:
request.user
If the user isn't authenticated, then Django will return an instance of django.contrib.auth.models.AnonymousUser. (per http://docs.djangoproject.com/en/dev/ref/request-response/#attributes)
Requirements --> Django 3, python 3
1) For add username to owner = models.ForeignKey('User') for save that, in the first step you must add from django.conf import settings above models.py and edit owner = models.ForeignKey('User') to this sample:
class Post(models.Model):
slug = models.SlugField(max_length=100, unique=True, null=True, allow_unicode=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, on_delete=models.CASCADE)
2) And for show detail Post, special owner name or family or username under the post, you must add the following code in the second step in views.py:
from django.shortcuts import get_object_or_404
.
.
.
def detailPost(request,slug=None):
instance = get_object_or_404(Post, slug=slug)
context = {
'instance': instance,
}
return render(request, template_name='detail_post.html', context=context)
3) And in the third step, you must add the following code for show user information like user full name that creates a post:
<p class="font-small grey-text">Auther: {{ instance.owner.get_full_name }} </p>
now if you want to use user name, you can use {{ instance.owner.get_username }}
or if you want to access short name, you can use {{ instance.owner.get_short_name }}.
See this link for more information.

Categories