I am building a simple social media app. AND i am trying to build a feature of adding users into post using ManyToManyField.
I am trying to access profile friends in Post's model instance "add_user" for tagging user.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,default='',unique=True)
full_name = models.CharField(max_length=100,default='')
friends = models.ManyToManyField("Profile",blank=True)
class Post(models.Model):
post_owner = models.ForeignKey(User,default='',null=True,on_delete = models.CASCADE)
post_title = models.CharField(max_length=500,default='')
add_user = models.ManyToManyField(User.profile.friends.all())
I am new in django and I have no idea how can i access user's friend in Post's model instance.
Any help would be much Appreciated.
Thank You in Advance.
You can't give a queryset as an argument for a ManyToManyField, just a class name.
add_users = models.ManyToManyField(User.profile.friends.all()) # you can't do this.
add_users = models.ManyToManyField(User) # Do this.
You shouldn't place you logic in your model's definition.
Do that in your views.
EDIT:
I suggest you use a ModelChoiceField and do the filtering logic there:
class AddFriendForm(forms.Form):
def __init__(self, *args, **kwargs):
try:
user = kwargs.pop('user')
except:
user = None
super(AddFriendForm, self).__init__(*args, **kwargs)
self.fields['friend'].queryset = user.profile.friends.all()
friend = forms.ModelChoiceField(queryset=User.objects.none())
And then in your view you initialize it like this:
def your_view(request):
form = AddFriendForm(user=request.user)
You cannot do
add_users = models.ManyToManyField(User.profile.friends.all())`
Because the models is evaluated once, and need to be non mutable values
You need to do :
add_user = models.ManyToManyField("Profile",blank=True)
And dont forget to add on your ManyToManyField:
related_name="XXX", null=True
Related
I am doing an online classroom project in Django where I created a model named create_course which is accessible by teachers. Now I am trying to design this as the teacher who creates a class only he can see this after login another teacher shouldn't see his classes and how to add students into that particular class I created
the course model
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
views.py
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
form.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
forms.py
from django import forms
from .models import course
class add_course(forms.ModelForm):
class Meta:
model = course
fields = ('course_name', 'course_id', 'course_sec', 'classroom_id')
Add one more field in course model that establish relationship with User model. Hence you can get the details about the teacher who has created course.
from django.contrib.auth.models import User
class course(models.Model):
course_name = models.CharField(max_length=200)
course_id = models.CharField(max_length=10)
course_sec = models.IntegerField()
classroom_id = models.CharField(max_length=50,unique=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
In your view function, you can check whether logged in user is same as the created of the requested course.
def teacher_view(request, *args, **kwargs):
# since this is course specific view, you will be passing an identiier or pk of the course as an argument to this function.
course_obj = Course.objects.get(id="identifier")
if request.user == course_obj.created_by:
# logged in user is same as the creator of the course
else:
# redirect
I would prefer creating permissions and having those in specific models. You can give it a try with that too. Let me know, if it doesn't work.
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 am working on a hard django project and I am stuck again. I have a field in the userprofile which is called troop:
class UserProfile(models.Model):
scout_username = models.OneToOneField(User, on_delete=models.CASCADE)
Group_Choice = Groups.Scout_Groups()
troop = models.SlugField(max_length=27, choices=Group_Choice, default='None', blank=False)
date_of_birth = models.DateField(default=date.today)
def __str__(self):
return '%s'% (self.scout_username)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
Then I have a form which fills in data which is sent to my stData model. Within the form the user can choose to add details about another user. Except they can only add details to another user who has the same troop details.
forms.py
from django import forms
from leaders.models import stData
from django.contrib.auth.models import User
from accounts.models import UserProfileManager, UserProfile
st_username_list=[
(None, 'Choose a user'),
(user1, 'user1'),
(i, 'no progress'),
]
class BadgeForm(forms.ModelForm):
def set_user(self, user):
global st_username_list
troop = user.userprofile.troop
userprofile = UserProfile.objects.all()
selected_st = userprofile.filter(troop=troop)
for st in selected_st:
username = str(st.st_username)
st_username_list.append((username, username))
st_username = forms.ChoiceField(choices=st_username_list)
class Meta:
model = stData
fields = ('st_username', 'Pioneer_Badge', 'Explorer_Badge', 'Adventurer_Badge', 'Proficiency_Badge', 'Other_Badge')
Please note
In the example above I used a global variable. I understand this is far from desired. I have since removed it thanks to the explanation of the proper way to do the filter (found after the line break). I'm only keeping this for education reasons for others who may find they had similar problems.
I pass through the user within my views like this:
user = request.user
user_form_setting = BadgeForm.set_user(self, user)
models.py
from django.db import models
from django.contrib.auth.models import User
from accounts.st_badge_list import st_List
class stData(models.Model):
Pioneer_Choices = st_List.Target_Badges()
Blue_Choices = st_List.Target_Badges()
Black_Choices = st_List.Target_Badges()
Proficiency_Choices = st_List.Proficiency_Badges()
Other_Choice = st_List.Other_Badges()
Pioneer_Badge = models.CharField(max_length=16, choices=Pioneer_Choices, default='None', blank=True)
Blue_Star = models.CharField(max_length=16, choices=Blue_Choices, default='None', blank=True)
Black_Star = models.CharField(max_length=16, choices=Black_Choices, default='None', blank=True)
Proficiency_Badge = models.CharField(max_length=22, choices=Proficiency_Choices, default='None', blank=True)
Other_Badge = models.CharField(max_length=27, choices=Other_Choice, default='None', blank=True)
st_username = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now=True)
print (User)
def __str__(self):
return '%s'% (self.st_username)
How would I go about having it so whatever user has the same troop details will appear within the st_username_list as a choice?
After researching and trying things with the code, I have been getting:
ValueError
Cannot assign "'user1'": "stData.st_username" must be a "User" instance.
I hope this is not too confusing.
Edit
Ok so I have found that I can filter the options for the st_username by doing
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['st_username'].queryset = UserProfile.objects.filter(troop='''user's troop''')
Problem update
My main issue now is that I am unable to pass through the user instance within the model. I have seen this question here. So I added this to my form's innit method:
self.user = kwargs.pop('user')
Yet when I try and use the user by going self.user I get the an unhelpful error KeyError saying user. The shell indicated this may be due to the self.user = kwargs.pop(user)
I believe this may be because I am not passing through the user. So when I call the form in my views, I tried form = BadgeForm(user=request.user) and got the same error.
my queryset looks like this now:
self.fields['scout_username'].queryset=UserProfile.objects.filter(troop=user.userprofile.troop)
Further Information:
To understand the problem better, I have passed through a set variable of the troop within the queryset. So in this case
self.fields['scout_username'].queryset=UserProfile.objects.filter(troop='BC')
Although now I get Error AttributeError:
'BadgeForm' object has no attribute 'name'
The shell links this with the formset from which I use the form with. The details I'm provided is:
line 435, in formset_factory
return type(form.__name__ + 'FormSet', (formset,), attrs)
I hope this makes more sense to you than to me! Any help would be greatly appreciated!
The final problem was within the use of the formset.
According to the docs, the proper way to add the kwargs is to do such:
BadgeFormsSet = formset_factory(BadgeForm)
formset = BadgeFormsSet(form_kwargs={'user': request.user})
Hope this helps any one else!
I have three models Person, User and Profile. Profile links a person to a user like this:
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
person = models.OneToOneField(
Person,
on_delete=models.CASCADE
)
In my person detail view I want to get the username through the person selected.
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
context = super(PersonDetailView, self).get_context_data(**kwargs)
profile = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
# this line is the problem I guess
user = User.objects.get(pk=profile.user.user_id)
context['user_person'] = user
return context
With this code I get the error
'QuerySet' object has no attribute 'user'
Maybe it is a silly question but I'm lost on this.
How do I get the user from The profile filtered from a person?
Thanks in advance, I hope I made mydelf clear enough.
EDIT
I got everything workin with Robert Townley answers, thank you.
The line that says:
profile = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
should instead grab the Profile from the queryset:
profile = Profile.objects.get(person_id=Person.objects.get(pk=self.kwargs['pk']))
If you do "filter()" you'll receive a queryset. If you do "get()" you'll receive the only object matching that queryset. You can also do:
profile_queryset = Profile.objects.filter(person_id=Person.objects.get(pk=self.kwargs['pk']))
profile = profile_queryset.first()
Note: Only do this if you're sure that the Profile object exists, or you'll get a DoesNotExist error.
Correct me if I'm wrong, but it looks like you are creating a relation table to connect a Person with a User.
You do not have to create relation tables in django.
Instead you should add a foreignkey
https://docs.djangoproject.com/en/1.11/ref/models/fields/#module-django.db.models.fields.related
As i can see, You can use simple soulution for your logic,
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
context = super(PersonDetailView, self).get_context_data(**kwargs)
context['user_person'] = self.request.user
# Just only one action
return context
Looks like you need this:
class PersonDetailView(DetailView):
model = Person
template_name = 'people/person_detail.html'
def get_context_data(self, **kwargs):
user = self.object.profile.user if hasattr(self.object, 'profile') else None
return super(PersonDetailView, self).get_context_data(user_person=user, **kwargs)
I am donig with a poll system for my class. I use model-form and create-view to serve the poll form. I use choices in in the field but I just find out that create-view only save the last value of the checkboxes and I want to save all the selected choices as a list maybe. I've tried to change the form_valid() method, but I just find out that I need to iterate all the fields to check wheather there are multipule choices. It's not flexible. And I can't figure out other solutions...
How can I meet this requirement? I am truly a newbie..
Thanks in advance.
Thank the friend below for replying in such a short interval after I raised my question. Here is my code.
models.py
CHOICES = (('m','Math'),('f','French'),('s','Science'),('l','literature'))
class Poll(models.Model):
[...]
subject = models.CharField(max_length = 5,choices = CHOICES, blank=True)
[...]`
forms.py
class PollForm(forms.ModelForm):
model = Poll
fields = [..., 'subject', ...]
widgets = {'subject':forms.CheckboxSelectMultiple}
views.py
class PollView(CreateView):
form_class = PollForm
template_name = 'poll.html'
Students can choose subjects they want.
It seems like you need to convert your model. If you could provide a sample of the structure that you are using it would be helpful. Still lets try solving your query. First you need identify that choices is nothing more than a many to many field. Saving it in the db should be a bit easier that way. Lets try taking an example with choices for a user:
class Choices(models.Model):
description = models.CharField(max_length=100)
class UserProfile(models.Model):
user = models.ForeignKey(User, blank=True, unique=True, verbose_name='profile_user')
choices = models.ManyToManyField(Choices)
def __unicode__(self):
return self.name
Now if you want to make a default form you could simply do something like:
class ProfileForm(forms.ModelForm):
Meta:
model = UserProfile
Now comes your main view. This can be editted and rendered to whatever your use case demands it to be:
if request.method=='POST':
form = ProfileForm(request.POST)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
#Implement this as a pre-save so that you can add additional value
profile.save()
else:
form = ProfileForm()
Hope this helps.