Django "Manager isn't accessible via UserProfile instances" - python

Here is my views.py
if request.user.is_authenticated():
changepass = request.user.userprofile.objects.get(user=request.user)
if changepass.force_password_change == True:
changepass.force_password_change = False
changepass.save()
return HttpResponseRedirect('/login/register/')
elif changepass.force_password_change == False:
return HttpResponseRedirect('/main/')
This line changepass = request.user.userprofile.objects.get(user=request.user) is the problem according to Django. I am trying to access force_password_change from UserProfile.
As the title suggests, I am getting the error Manager isn't accessible via UserProfile instances.
Here is my models.py for reference.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
force_password_change = models.BooleanField(default=True)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)

You already have the UserProfile instance when you done request.user.userprofile,
at this point, you have a Instance of UserProfile. you can't use the object manager (.objects) from that.
you only need
changepass = request.user.userprofile
Another way to get the userprofile object, is doing
UserProfile.objects.get(user=request.user)

You can't access a Manager through a Model instance. In your case, request.user is an instance of the User class.
To access the manager, you need to use the UserProfile class directly.
Although, for what you're trying to accomplish, it's much easier to transverse the database through the request's user object:
changepass = request.user.userprofile

Try using just
changepass = UserProfile.objects.get(user=request.user)

Related

How to read Objects from ManyToMany Relation class in django

I have made a class called friend where i want to connect users as followers. Here From this class i am unable to read the users those are following another user. For Eg if 'a' user fllows 'b' user. Then i want to get the names of user that followed b from the user id of b and display them as followers of a. This class is also not storing the userid of the following user and followed user. I am new to many to many relation field. Kindly help.
Code in Models.py
class Friend(models.Model):
users = models.ManyToManyField(User)
current_user = models.ForeignKey(User, related_name='follower', null=True,on_delete=models.CASCADE)
#classmethod
def make_friend(cls, current_user, new_friend):
friend, created = cls.objects.get_or_create(
current_user = current_user
)
friend.users.add(new_friend)
Its function in views.py is
def change_friends(request, operation, pk):
friend = User.objects.get(pk=pk)
if operation == 'add':
Friend.make_friend(request.user, friend)
elif operation == 'remove':
Friend.lose_friend(request.user, friend)
return redirect('home')
Its url in urls.py is
path('connect/<operation>/<pk>)',views.change_friends, name='change_friends')
In your methods, you are not saving your modifications.
When you do friend.make_friend(...), after that you should save your friend object: friend.save(), so m2m fields can be also saved.
Same goes for your other methods updating users fiels of a Friend object.
Rather than create a friend model you can create a custom user model where you define the many to many relationship. If you define the ManyToManyField with symmetrical=False then it will not be symmetrical
class CustomUser(AbstractUser):
friends = models.ManyToManyField('self', symmetrical=False, related_name='followers')
You need to define this model as your user model in your settings
AUTH_USER_MODEL = 'you_app.CustomUser'
Now you can use this relationship directly from the user instance itself
def change_friends(request, operation, pk):
friend = CustomUser.objects.get(pk=pk)
if operation == 'add':
request.user.friends.add(friend)
elif operation == 'remove':
request.user.friends.remove(friend)
return redirect('home')
Now your CustomUser instances will have 2 relationships that can be queried
request.user.friends.all()
request.user.followers.all()

How to add a user to a ManyToManyField when creating User in Django?

Models.py:
class RegularUser(MyUser):
MyUser.is_staff = False
MyUser.is_superuser = False
class Meta:
verbose_name = 'Usuario Regular'
verbose_name_plural = 'Usuarios Regulares'
class AdminUser(MyUser):
usuarios = models.ManyToManyField(RegularUser, help_text="Selecciona los usuarios que administra", blank=True)
MyUser.is_staff = True
class Meta:
verbose_name = 'Administrador'
verbose_name_plural = 'Adminsitradores'
I want the next: I log in the admin site as AdminUser, which have staff permission. Then I can create RegularUsers. When I create a new RegularUser I want link this Regular User to the AdminUser through the ManyToManyField so this RegularUser owns to the AdminUser. And the AdminUser could manage this RegularUser in the adminSite.
I want some like this:
class RegularUserCreationForm(forms.ModelForm):
...
...
#receiver(post_save, sender=RegularUser)
def link_user_admin(sender, instance, created, **kwargs):
if created:
instance.adminuser = request.user
But adminuser isn't a field of RegularUser. And using request in signals is forbidden. Can someone help me please?
Well. I have found the solution. I need to use the request in the post_save method. However, you can't use it in Django signals, so it's possible to use the Django save_model method which you can get access to the request.
def save_model(self, request, obj, form, change):
if obj:
# Save the object
super().save_model(request, obj, form, change)
# Add the user instance to M2M field of the request.user (The admin User) who create the RegularUser
request.user.adminuser.usuarios.add(obj)

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

Adding instances into a different model

I am trying to make a notification app for my Django project.
I have this as one of my views:
class LikePostToggle(RedirectView):
def get_redirect_url(self,pk):
obj = get_object_or_404(UserPost,pk=pk)
user = self.request.user
if user.is_authenticated():
if user in obj.likes.all():
obj.likes.remove(user)
else:
obj.likes.add(user)
#Add notification to UserNotification model
#Auto fill all fields
return obj.get_absolute_url()
And this is my UserNotification model:
class UserNotification(models.Model):
user = models.ForeignKey(User,related_name='user',null=True)
post = models.ForeignKey('feed.UserPost',related_name='post-notification')
timestamp = models.DateTimeField(auto_now_add=True)
notify_type = models.CharField(max_length=6)
read = models.BooleanField(default=False)
def __str__(self):
return self.user
In the model I think I want the user field to be the user committing the action (Liking, commenting, etc.).
My question is how might I go above making it so that whenever someone likes a post or comments and therefore triggers the LikePostToggle view it also adds an instance to the UserNotification model so that the user can be notified?
You can create an instance with UserNotification() then call save(), or you can use the create shortcut.
In the view you have access to the post and the logged in user. The timestamp will be added automatically and read will default to False, so you just have to decide what to set notify_type to:
obj.likes.add(user)
#Add notification to UserNotification model
notification = UserNotification.objects.create(
user=self.request.user,
post=obj,
notify_type="???"
)

Trouble with signals when inheriting from an abstract class

My app has different sort of users (parents, teachers, students) and I created a Profile abstract class to inherit from. I'm trying to use a receiver function so that whenever a user is created, a profile is also created.
In the admin page, when I try to create a Teacher Object, I need to create a User object first, but when I create a user object, I run into an error "AttributeError: type object 'Profile' has no attribute 'objects'".
I suspect this is because Profile is an abstract class, so if a User is created, it causes an error to create a Profile? If so, what's the better way to do this? I'm just trying to manually create a Teacher object in the admin page.
#models.py
class Profile(TimeStampedModel):
user = models.OneToOneField(User, on_delete=models.CASCADE)
sex = models.CharField(max_length=1, choices=SEX)
user_type = models.CharField(max_length=100, choices=USER_TYPE)
class Meta:
abstract = True
class Teacher(Profile):
user_type = 'teacher'
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)

Categories