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()
Related
Whenever, I call form.save() I get "django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_id"
I think this might be because I have a oneToOneField and Django is trying to save to UserAgreedToLegal and User Model but the User model already has that ID, so the unique constraint fails, but not sure.
I am wondering how I can fix this issue. I listed my model, form, and view code below
models.py
import uuid
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone as django_timezone
class UserAgreedToLegal(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
agreed_first_terms_of_service = models.BooleanField(default=False, blank=False, null=False)
date_agreed = models.DateField(null=True, default=django_timezone.now)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
def __str__(self):
return self.user.username
forms.py
from django import forms
from legal.models import UserAgreedToLegal
class TermsOfServiceAgreementForm(forms.ModelForm):
class Meta:
model = UserAgreedToLegal
fields = [
'agreed_first_terms_of_service'
]
views.py
if request.method == 'POST':
form = TermsOfServiceAgreementForm(request.POST)
if form.is_valid():
form.clean()
terms_of_service_agreement = form.save(commit=False)
terms_of_service_agreement.user = request.user
terms_of_service_agreement.save()
The result is
django.db.utils.IntegrityError: UNIQUE constraint failed: legal_useragreedtolegal.user_id
I think this might be because I have a OneToOneField and Django is trying to save to UserAgreedToLegal and User Model but the User model already has that ID, so the unique constraint fails, but not sure.
You are correct, a OneToOneField is in essence a ForeignKey with unique=True. It thus makes no sense to visit this view a second time.
You can check if the person already has agreed to the legal terms, and if that is the case redirect to a page, for example a view that renders a page to explain that the user already agreed, so something like:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def my_view(request):
if UserAgreedToLegal.objects.filter(user=request.user).exists():
return redirect('name-of-some-view')
if request.method == 'POST':
# …
# …
where the name-of-some-view should point to a view that will render that page.
The reason it was failing was because there was a OneToOne relationship with the django user model, and when I called form.save() it was trying to save a new row (insert a new user) into both User and my model and then it would see that this user_id already exists in my model and it would tell me that it cannot be done because then it would violate a rule that I placed of having only a one to one relationship because if it did save each one user would have many records. That would create a one to many instead of a one to one.
Instead, what I needed to do was to tell django that I don't want to insert a new record in my model, or to update it if that record already exists and if not create it while maintaining its relationship with the User model.
I had to pass in an instance for Django Forms to know that I already have this model and I don't want to update this instance.
here is the code that worked for me
if request.method == 'POST':
my_user = UserAgreedToLegal.objects.get_or_create(user=request.user)[0]
form = TermsOfServiceAgreementForm(request.POST, instance=my_user)
if form.is_valid():
form.clean()
terms = form.save(commit=False)
terms.user = request.user
terms.save()
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.
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
i created a model
class ThisUser(models.Model):
created = models.DateTimeField(auto_now=True)
message = models.CharField(max_length=120)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.user
I want to store message specifically for the user who is authenticated.
right now this will give me all user who is available in my user model.
Please help
user = models.OneToOneField(User, on_delete=models.CASCADE)
Instead of foriegn key use one to one relation
Well you are suppose to take care of that at view level and not model level,
for example this is how I create a new Album:
#login_required
def make_album(request):
if request.method == 'POST':
form = AlbumCreationForm(request.POST)
if form.is_valid():
new_album = core_models.Album(name=form.cleaned_data['name'], description=form.cleaned_data['description'], user=request.user)`
You can use request.user.id to get user's id for further use.
I am hacking Django, as I am new to it, to create a website to which user can login and can answer some questions. For logged in user I intend to store their username, question id and response to the question. However, after trying for multiple hours I have been completely unsuccessful. Below I have given snippets of Models.py and Views.py
Models.py - I am copying only UserProfile class and Userresponse class which are needed to create the User Profile and User Response table
# Model class for creating user
class UserProfile(models.Model):
user = models.OneToOneField(User)
def __str__(self):
return self.user.username
# Model class for getting user response
class UserResponse1(models.Model):
user = models.ForeignKey(UserProfile, default=0)
questoinId = models.ForeignKey(Question)
option = models.IntegerField(default=0)
```Views.py``
def response(request, question_id):
q = UserResponse1()
if request.user.is_authenticated():
q.user = request.user.username
q.questionId_id = question_id
q.option +=request.POST['choice']
q.save()
# Redisplay the question voting form.
return HttpResponseRedirect(reverse('polls:overallResults'))
However, on running above I get following error - Cannot assign "u'abc123'": "UserResponse1.user" must be a "UserProfile" instance.
abc123 is the login name of the user. I am not able to figure out the reason for this error. Any help on fixing this error so that I can write the data to UserResponse1 table, will be very helpful.
I am using Django 1.8 on Python 2.7
q.user is a foreign key to the UserProfile table, so you have to assign a user profile instance.
Since you have access to the user with request.user you can access the user profile using the one to one field.
user_profile = request.user.userprofile
q.user = user_profile