I need to get the current logged in user in Django form. I need it to get the domain from his email and accordingly fetch the list of other users with similar domain. Here is my code so far:
forms.py
class AuthUserCheckbox(forms.Form):
choice = forms.MultipleChoiceField(choices=[], widget=forms.CheckboxSelectMultiple, required=True)
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
self.user_email = self.user.email.split('#')[1]
super(AuthUserCheckbox, self).__init__(*args, **kwargs)
self.fields['choice'] = forms.MultipleChoiceField(choices=[(i.id, i.email)
for i in User.objects.all()
if not i.is_active and
self.user_email in i.email
])
views.py
#login_required
def auth_users(request):
form = auth_users(data=request.POST, user=request.user)
return render(request, 'todoapp/auth_users.html', context={'form': AuthUserCheckbox()})
You need to pass the request's user into your form constructor and then place that form in context. Your view needs to look something like:
#login_required
def auth_users(request):
form = AuthUserCheckbox(request.POST, user=request.user)
return render(request, 'todoapp/auth_users.html', context={'form': form})
Of course, the above is an incomplete view, because you shouldn't just grab POST like that, but that is not the question.
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)
created_by = models.ForeignKey(User,on_delete=models.CASCADE)
here if I use "the created_by" field in forms it appears to be a drop-down menu where every user is showing but I want to automatically save the user who creates the object
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')
You can inject the logged in user to the .created_by of the .instance in the form, so:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def teacher_view(request, *args, **kwargs):
if request.method == 'POST':
form = add_course(request.POST, request.FILES)
if form.is_valid():
form.instance.created_by = request.user
form.save()
return redirect('name-of-some-view')
else:
form = add_course()
return render(request, 'teacherview.html', {'add_courses': form})
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.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CourseForm instead of
add_course.
Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from course to Course.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
In your view use commit=False to stop the form from saving until you add the created_by field.
def teacher_view(request, *args, **kwargs):
form = add_course(request.POST or None)
context = {}
if form.is_valid():
course = form.save(commit=False)
course.created_by = request.user
course.save()
return HttpResponse("Class Created Sucessfully")
context['add_courses'] = form
return render(request, 'teacherview.html', context)
I'm trying to add chat functionality to my app and right now I can add users to existing chats but what I need to do is filter users that are not already in the chat in the form.
I'm using django form with passed arguments to filter my users but I'm not getting any results.
My Chat model has a m2m field to user called 'users' and my User has a m2m field called 'friends' with itself.
forms.py
class AddUserToChatForm(forms.ModelForm):
class Meta:
model = Chat
fields = ('users', )
def __init__(self, chat, friends, request, *args, **kwargs):
self.request = request
self.chat = chat
self.friends = friends
super(AddUserToChatForm, self).__init__(*args, **kwargs)
self.fields['users'] = forms.ModelMultipleChoiceField(queryset=self.request.user.friends.exclude(user__in=chat.users.all()),
widget=forms.CheckboxSelectMultiple
(attrs={'class': 'add-people-to-chat-form'}),
label='Friends:')
views.py
def add_users_to_chat(request, pk):
chat = Chat.objects.get(pk=pk)
friends = request.user.friends.all()
if request.method == 'POST':
form = AddUserToChatForm(chat, friends, request, request.POST)
if form.is_valid():
users_to_add = form.cleaned_data['users']
chat.users.add(*users_to_add)
chat.save()
return redirect('messages')
else:
form = AddUserToChatForm(chat, friends, request, instance=None)
return render(request, 'add_users_to_chat.html', {'form': form, 'chat': chat, 'friends': friends})
EDIT
Looks like my exclude statement has no effect because when I switch it to filter the set returns all of the user friends.
UPDATE
I was able to retreive the required users using difference method like this:
in view:
chat = Chat.objects.get(pk=pk)
friends = request.user.friends.all()
chat_users = chat.users.all()
queryset = friends.difference(chat_users)
and pass it to the form
def __init__(self, queryset, request, *args, **kwargs):
self.request = request
self.queryset = queryset
super(AddUserToChatForm, self).__init__(*args, **kwargs)
self.fields['users'] = forms.ModelMultipleChoiceField(queryset=self.queryset,
widget=forms.CheckboxSelectMultiple
(attrs={'class': 'add-people-to-chat-form'}),
label='Friends:')
getting users with difference method but now when I try to submit the form I get this error: Calling QuerySet.filter() after difference() is not supported.
Debugger quits execution on this line in view:
users_to_add = form.cleaned_data['users']
As the fields are automatically generated by the ModelForm, it is best to define only the a queryset in init:
def __init__(self, chat, friends, request, *args, **kwargs):
self.request = request
self.chat = chat
self.friends = friends
super(AddUserToChatForm, self).__init__(*args, **kwargs)
self.fields['users'].queryset = self.request.user.friends.exclude(user__in=chat.users.all())
I was able to achieve the wanted result by querying using exclude after all:
in view:
queryset = friends.exclude(id__in=chat_users)
and now everything works as intended
When user requests object, when user wants to enter detail view's page, I want to check weather user have subscription and redirect him. But I don't know how to request user and validate him in DetailView. This is what at least I could did.
class PropertyDetailView(LoginRequiredMixin, DetailView):
login_url = '/login/'
model = Property
template_name = 'project/property/property_detail.html'
def post(self, *args, **kwargs):
if self.request.user.sale_tariff is None:
return redirect('/')
Are there any ways how to validate DetailView?
Overriding the get request something like this
def get(self, *args, **kwargs):
if self.request.user.sale_tariff is None:
return redirect('/')
else:
return render(template_name)
I am writing a django ListView with FormMixin, but it can't handle form errors. The model limits input to 140 characters, when I inspect and change limit to 200 and submit I get
'PostListView' object has no attribute 'object_list'"
Here's the code
class PostListView(FormMixin, generic.ListView):
model = Post
form_class = PostForm
paginate_by = 10
template_name = 'index.html'
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
form = PostForm(request.POST)
if form.is_valid():
form.save()
return super().form_valid(form)
else:
return self.form_invalid(form)
With everything working normally, it saves the data and displays the list. On error, no error, it fails.
EDIT
As #crimsonpython24 has said, ListView is for displaying data. I opted to use a basic view
def index(request):
'''deal with post method first'''
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect(reverse('index'))
else:
form = PostForm
posts = Post.objects.all()
return render(request, 'index.html', {'form':form, 'posts':posts})
This allows for invalid form data to be returned for correction, and also allows viewing of posts
The point is that ListView is only supposed to view objects. If you have a form in your view, try to go for one of the edit views, which lets you create, update, and delete (now I'm assuming that you also handle a form in this view).
I can't exactly describe how ListView causes your problem other than it does not fit your purpose and there are better alternatives.
EDIT
Now you're concatenating a FormView and ListView. However, I will still recommend going for a FormView as a ListView doesn't have a form_class attribute. It's easy, though. Let's say you have this FormView class:
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm # Now you can simply do this to your form
success_url = '/thanks/'
def form_valid(self, form):
form.send_email()
return super().form_valid(form)
and then simply pass in context data to make it behave partially like a ListView:
class ContactView(FormView):
# whatever you have here already
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
return context
So now your new view will render both your form and context data. Seeing as both these views don't require a primary key to operate, I don't see any problem implmenting this.
In my app, I want the following behaviour:
User goes to contact form url
User fills up the contact form
(a) If user is logged in, validate and submit the form
(b) If user is not logged in, redirect to login form for logging in and then if users credentials are validated, submit the form.
In my views.py, I have:
#method_decorator(login_required, name='post')
class ContactView(FormView):
template_name = 'extras/contact.html'
form_class = ContactForm
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form, **kwargs)
else:
return self.form_invalid(form, **kwargs)
def form_valid(self, form):
instance = form.instance
instance.request_user = self.request.user
instance.save()
messages.success(self.request, "Thank you for contacting us! We will reach you soon.")
return super().form_valid(form)
def get_success_url(self):
return reverse('main_home')
The idea of including a post method was taken from this SO Answer
This does not work. The user is being redirected to login form, logged in, but displays a blank form and entered information before redirection is lost.
How can I resolve this problem, any hints?
When you redirect a post request to the login page, you’ll lose the post data. Therefore you should redirect GET requests as well, so that the user logs in before they fill out the contact form. You can do this by decorating the dispatch method.
#method_decorator(login_required, name='dispatch')
class ContactView(FormView):