How can I retrieve form data from Django CreateView? - python

I have a Django blog where the users can set the status of each post (active, inactive) when creating them. I am using Django's generic class-based views and would like to redirect the user to their created post only when the status is set to "active", otherwise they should be redirected to the homepage. How can I retrieve this submitted info from the form to create an if statement? For example: if status == "a"...
views.py
from .models import Listing
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic import CreateView
class PostCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Post
fields = ['title', 'status', 'content']
template_name = 'blog/post-form.html'
success_message = 'Your post has been created.'
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)

I think "redirect" is not valid withing the method (form_valid) so you should definitely put something like def post, and get the value in request.data. I'm going to try showing you a code that is working for me in production. You let me know if it was the right response.
class LoginFormView(FormInvalidMessageMixin, LoginView):
template_name = "clientes/login.html
def post(self, request, *args, **kwargs):
username = self.request.POST.get('username')
password = self.request.POST.get('password')
tipo_cuenta = self.request.POST.get('tipo-cuenta')
tipo_cuenta = tipo_cuenta.strip()
user = authenticate(username=username, password=password)
if user:
if has_group(user, 'admin'):
messages.success(request, _('Not for admin'))
return redirect('/login')
cliente = Usuario.objects.filter(usuario=user).first()
sucursal = Sucursal.objects.filter(usuario=user).first()
empleado = Empleado.objects.filter(usuario=user).first()
if tipo_cuenta == 'Punto afiliado':
login(self.request, user)
return redirect('/envios')

Related

How to redirect user from registration page to profile if user is already registered?

I am using Django class-based views for my project and trying to redirect user from registration view if he is already authenticated. I've done it already with LoginView and it was pretty simple and looked just like adding few lines of code:
class Login(LoginView):
authentication_form = CustomAuthenticationForm
redirect_authenticated_user = True
LOGIN_REDIRECT_URL = "core:profile"
So after going to url for login, user ends up at his profile url. Absolutely simple and works perfectly.
However, there is no CBV for registration and therefore CreateView should be used, which doesn`t have any attributes for checking if user is authenticated.
The one method of doing something similar is UserPassesTestMixin, but it only gives me 403 Forbidden if user is authenticated, not redirect.
Here is my current registration view:
class Registration(UserPassesTestMixin, CreateView):
form_class = RegistrationForm
template_name = "registration/user_form.html"
success_url = reverse_lazy("core:profile")
def test_func(self):
return self.request.user.is_anonymous
def form_valid(self, form):
print(self.kwargs)
self.object = form.save(commit=True)
self.object.is_active = True
self.object.save()
login(self.request, self.object, backend="core.auth_backend.AuthBackend")
return HttpResponseRedirect(self.success_url)
Maybe somebody have done it already?
Would be very grateful for every advice!
In your Registration class, add a get method and remove your test_func:
def get(self,request,*args,**kwargs):
if self.request.user.is_authenticated:
return HttpResponseRedirect('redirect_url')
return super().get(request,*args,**kwargs)

How do I make my Django dropdown form show items owned by a user and not all users?

I am having trouble displaying items owned only by specific users, rather than each user getting to see all items in my database. Below is an example of a non-superuser who has access to all items in my database when this user should only have access to the ones they created
image of dropdown menu with all items instead of just some
Below are the Form, View, and Models I have created in attempt to do this.
forms.py
class RoutineForm(forms.ModelForm):
"""creates a form for a routine"""
class Meta:
model = Routine
fields = ['workout']
labels = {'workout': 'Workout'}
Here is the views.py
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
#login_required
def routine(request):
"""display a dropdown of all workouts for a user"""
if request.method != 'POST':
form = RoutineForm()
else:
form = RoutineForm(data=request.POST)
if form.is_valid():
new_routine = form.save(commit=False)
new_routine.save()
return redirect('index')
context = {'workouts':workouts, 'form':form}
return render(request, 'routine_workouts_app/routine.html', context)
and finally, the models.py file
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Workout(models.Model):
"""A workout group the user will use to workout"""
text = models.CharField(max_length=200) #titles should not be too long
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
"""Return a string representation of the model"""
return self.text
class Routine(models.Model):
"""Shows a routine"""
workout = models.ForeignKey(Workout, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return 'this is a routine'
Am I missing some sort of filter? Something Fundamental? I have been able to filter some other views that I have made. For example:
#login_required
def workouts(request):
"""This is the page that will display all the workout groups"""
workouts = Workout.objects.filter(owner=request.user).order_by('text') #filter by user ownership
context = {'workouts': workouts}
return render(request, 'routine_workouts_app/workouts.html', context)
on line 4 of this snippet, I have successfully filtered items that only belong to a specific user. But this is not a form, just a display on an html file. I have tried to put a similar line in the routine view function but it did not work. Any suggestions?
You can add a parameter to the constructor of the RoutineForm, that will filter the queryset specified to link to a Workout. This thus means that the form looks like:
class RoutineForm(forms.ModelForm):
"""creates a form for a routine"""
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['workout'].queryset = Workout.objects.filter(owner=user)
class Meta:
model = Routine
fields = ['workout']
labels = {'workout': 'Workout'}
In the view, we then can construct a Form where we pass the logged in user to the constructor of the form:
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
#login_required
def routine(request):
"""display a dropdown of all workouts for a user"""
if request.method != 'POST':
form = RoutineForm(user=request.user)
else:
form = RoutineForm(data=request.POST, user=request.user)
if form.is_valid():
form.instance.owner = request.user
new_routine = form.save()
return redirect('index')
context = {'workouts':workouts, 'form':form}
return render(request, 'routine_workouts_app/routine.html', context)

How to redirect to previous page in custom DeleteView?

I have the following custom DeleteView:
class CarDeleteView(LoginRequiredMixin, DeleteView):
model = Car
context_object_name = 'car'
template_name = 'cars/car_confirm_delete.html'
success_message = "%(name)s is pending removal"
def get_success_url(self):
return reverse('car-list')
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
name = self.object.name
owner = self.object.owner
if owner != self.request.user:
messages.error(request, f'You don\'t have permissions to remove {name}')
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
# DO Stuff
return redirect(reverse('car-list'))
I'm trying to redirect to previous entry point when user isn't the owner (so he can't delete). But HttpResponseRedirect(request.META.get('HTTP_REFERER')) gives me the URL of the current page (car_confirm_delete.html) and not the previous one. How can I make it go to previous one? Maybe that's because Django does POST?
You need to import HttpResponseRedirect
from django.http import HttpResponseRedirect
and then
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

How can I assign the logged in (authenticated) user to the form data they submit?

I am developing an employee feedback interface with Django. They shall be able to log in and submit a complaint. That complaint is supposed to be stored in the database with the user who submitted it as an attribute.
I have tried to somehow pass the user to the form so that the form saves the authenticated user's username, but I haven't been able to pass data from a view to a form.
I have been able to integrate a ModelChoiceField() to the ModelForm, but that lets the authenticated user manipulate the username that the complaint is going to be associated with.
models.py:
from django.db import models
from django.contrib.auth.models import User
class Complaint(models.Model):
complaint_text = models.CharField(max_length=1000, default='')
switch_schedule_yes_or_no = models.BooleanField(default=True)
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
views.py:
from .forms import ComplaintForm
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
#login_required()
def complaint_view(request):
form = ComplaintForm(request.POST)
if form.is_valid():
form.save()
form = ComplaintForm()
context = {
'form': form,
}
return render(request, 'complaint.html', context)
forms.py:
from django import forms
from .models import Complaint
from django.contrib.auth.models import User
class ComplaintForm(forms.ModelForm):
complaint_text = forms.CharField(max_length=1000)
switch_schedule_yes_or_no = forms.BooleanField()
user = forms.ModelChoiceField(queryset=User.objects.all())
class Meta:
model = Complaint
fields = ['complaint_text', 'switch_schedule_yes_or_no', 'user']
If it is possible to somehow design this is a way that allows the complaint to be associated with the authenticated user, that would be amazing! Be it by passing parameters from a view to a form or by using user-individual URLS. I have been trying to solve this for days now.
Cheers!
You can use request.user to access the authenticated user and associate with you Complaint object. You don't need the user field in the ComplaintForm form.
#login_required()
def complaint_view(request):
form = ComplaintForm(request.POST)
if form.is_valid():
complaint = form.save(commit=False) #don't commit to DB
complaint.user = request.user #access the user
complaint.save() # save and commit to DB
form = ComplaintForm()
context = {
'form': form,
}
return render(request, 'complaint.html', context)
Try the following Class Based View Approach
In your form, you can ommit this line:
user = forms.ModelChoiceField(queryset=User.objects.all())
from django.views import generic
from my_app.forms import ComplaintForm
class ComplaintView(generic.CreateView):
template_name = "complaint.html"
form_class = ComplaintForm
def form_valid(self, form):
form.instance.user = self.request.user # This is where what you want happens
super().form_valid(form)
And to add the login required constraint, you can use the LoginRequiredMixin:
from django.contrib.auth.mixins import LoginRequiredMixin
class ComplaintView(LoginRequiredMixin, generic.CreateView):
pass

Django form is still full after sign up

I have an app in django 1.11. Below is the view with the form where the user can sign up for the event, after saving he gets a message about the details - on the same page, at the same url. But, after saving the form is completed and after pressing F5 the next saving is performed. How can I avoid this?
I think something with the form_valid method is wrong.
class EventDetailView(DetailView, CreateView):
model = models.Event
form_class = forms.ParticipantForm
context_object_name = 'event'
template_name = 'events/event_detail.html'
def get_success_url(self):
return reverse('events:detail', kwargs={'slug': self.kwargs['slug'], 'pk': self.kwargs['pk']})
def form_valid(self, form):
self.object = form.save()
context = self.get_context_data()
context['registered_event'] = context['event']
return self.render_to_response(context)
After a successful form submission, you should redirect to prevent duplicate submissions.
def form_valid(self, form):
self.object = form.save()
return redirect(self.get_success_url())
Remember to add the import
from django.shortcuts import redirect
use flash message to show messages.
from django.contrib import messages as flash_messages
flash_messages.success(request, "Your Message Here")
and refresh page.

Categories

Resources