success_url from UpdateView to DetailView with pk in django - python

I make my own group permission page self with ListView to show Django Group list with a link to DetailView with pk and then give the change link to change the permissions with UpdateView.
I want to make the success_url of UpdateView to DetailView with pk, how to do this.
my code like:
views.py
class GroupCreation(PermissionRequiredMixin, CreateView):
permission_required = 'add_group'
model = Group
form_class = GroupCreateModelForm
success_url = reverse_lazy('account:group_list')
template_name = 'accounts/groups/group_creation.html'
class GroupsListView(PermissionRequiredMixin, ListView):
permission_required = 'view_group'
allow_empty = True
model = Group
ordering = 'name'
template_name = 'accounts/groups/groups_list.html'
form = GroupCreateModelForm
extra_context = {'form': form, }
class GroupDetailView(PermissionRequiredMixin, DetailView):
permission_required = 'view_group'
model = Group
template_name = 'accounts/groups/group_detail.html'
class GroupUpdateView(PermissionRequiredMixin, UpdateView):
permission_required = 'change_group'
model = Group
fields = ('permissions',)
template_name = 'accounts/groups/group_update.html'
success_url = reverse_lazy('account:group_detail')
urls.py
path('groups/', views.GroupsListView.as_view(), name='group_list'),
path('groups/<int:pk>/', views.GroupDetailView.as_view(), name='group_detail'),
path('groups/<int:pk>/change/', views.GroupUpdateView.as_view(), name='group_change'),
path('groups/create/', views.GroupCreation.as_view(), name='group_creation'),

You can use the get_success_url method in your UpdateView instead of success_url attribute; This way you can access the edited object's pk:
def get_success_url(self):
return reverse_lazy('account:group_detail', kwargs={'pk': self.object.pk})

Related

CreateView and UpdateView based class are not working in Django Project

I have Django in Which there is app called Listing and it's model as follows but CreateView and UpdateView are not woking for model.
I am also using mixins but I have implemented Custom User , so is that cuases a problem?
getting error
in get_form return form_class(**self.get_form_kwargs())
TypeError: 'ListingForm' object is not callable
Any other user is updating listing of others, UserPassesTestMixin not working
import uuid
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
User = get_user_model()
class Listing(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
...other fields
CreateView
class ListingCreateView(LoginRequiredMixin, CreateView):
model = Listing
form_class = ListingForm()
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
UpdateView
class ListingUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Listing
form_class = ListingForm()
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
def test_func(self):
listing = self.get_object()
#print(self.request.user, listing.owner)
if(self.request.user == listing.owner):
return True
else:
return False
forms.py
from django import forms
from .models import Listing
class ListingForm(forms.ModelForm):
class Meta:
model = Listing
fields = ['price', 'sqft', 'acre', 'title', 'description', 'address', 'city', 'state',
'country', 'zipcode', 'photo_main', 'photo_1', 'photo_2', 'photo_3', 'photo_4', 'photo_5']
Tysm for solving in advance!
You are missing form_class in your update and create view. You need to be add your forms name.
CreateView
class ListingCreateView(LoginRequiredMixin, CreateView):
model = Listing
form_class = your form name
fields = blah blah blah
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
UpdateView
class ListingUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Listing
form_class = your form name
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
def test_func(self):
listing = self.get_object()
#print(self.request.user, listing.owner)
if(self.request.user == listing.owner):
return True
else:
return False

Django Custom Queryset Using Listview if Parameters Exist in URL

I have a listview for my blog:
#views.py
class BlogListView(ListView):
model = Blog
template_name = 'blog/index.html'
context_object_name = 'blogs'
ordering = ['-date_posted']
paginate_by = 5
#urls.py
path('', BlogListView.as_view(), name='blog-index'),
In my model I have different type of blogs, such as video blog or text blog. my model is like this:
class Blog(models.Model):
TYPE = (
('Video', 'Video'),
('Text', 'Text'),
)
type = models.CharField(max_length=10, choices=TYPE, default='Text')
Now I want to use request.GET.get('type') to query different types. For example if I go to the url, 127.0.0.1:8000/?type=video I want only blog that are the type video to show. Is it possible to do this with only this listview, or do I have to create others. I need help with making of this feature.
Yes, you can implement this in the ListView by overriding the .get_queryset(…) method [Django-doc]:
class BlogListView(ListView):
model = Blog
template_name = 'blog/index.html'
context_object_name = 'blogs'
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self):
type = self.request.GET.get('type')
qs = super().get_queryset()
if type is not None:
return qs.filter(type__iexact=type)
return qs

Updating a user model in Django when they fill out a form on a different model

I am struggling to work out how to achieve something and would appreciate someone suggesting the correct Django way to do it.
I have a custom user model which is fairly basic but includes a BooleanField which says whether they have filled out a voluntary equality and diversity form. There is a very basic model which holds the equality and diversity form data without any reference to the users which filled out each response. What I want is this, when a user fills out a valid equality and diversity form it puts True in the user model box to say they have filled out the form.
I would be massively appreciative if anyone knows the correct way to do this as I am tying myself up in knots and have got myself quite confused.
Here is a simplified version of the code:
users/models.py
class CustomUser(AbstractUser):
# Has the user completed the EDI form?
edi = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('profile', args=[str(self.username)])
equality_diversity/models.py
class EqualityDiversity(models.Model):
age = models.CharField(max_length=8, choices=AGE_CHOICES)
ethnicity = models.CharField(max_length=64, blank=True, null=True)
... (etc)
equality_diversity/views.py
class EqualityDiversityView(LoginRequiredMixin, CreateView):
model = EqualityDiversity
template_name = 'equality_diversity.html'
form_class = EqualityDiversityForm
login_url = 'login'
success_url = '/'
def form_valid(self, form):
return super().form_valid(form)
class EqualityDiversityView(LoginRequiredMixin, CreateView):
model = EqualityDiversity
template_name = 'equality_diversity.html'
form_class = EqualityDiversityForm
login_url = 'login'
success_url = '/'
def form_valid(self, form):
# this is a view, You have self.request
self.request.user.edi = True
# apply changes to db
self.request.user.save()
return super().form_valid(form) # redirects to success_url
or better
class EqualityDiversityView(LoginRequiredMixin, CreateView):
model = EqualityDiversity
template_name = 'equality_diversity.html'
form_class = EqualityDiversityForm
login_url = 'login'
success_url = '/'
def form_valid(self, form):
# form.instance is an instance of the model that the form defines in META
form.instance.edi = True
# apply changes to db
form.instance.save()
return super().form_valid(form) # redirects to success_url

How can I convert my class-based view to function-based views? - Django

I am trying to change all my class-based views to function-based views and I am having difficulty converting the following class:
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Post
fields = ['image', 'title', 'category', status', 'description']
template_name = 'blog/post-form.html'
success_message = 'Your post has been updated.'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
def get_context_data(self, **kwargs):
context = super(PostUpdateView, self).get_context_data(**kwargs)
context['title'] = 'Update post'
context['submit'] = 'Update'
return context
def get_success_url(self):
author = self.object.author
return reverse_lazy( 'profile', kwargs={'author': author.username})
The function and form should do exactly what this class-based view does, so if anyone can help me out, please let me know.
You can specify a .form_class attribute [Django-doc] in an UpdateView (as well as in a CreateView). So we can create a form like:
# app/forms.py
from django import forms
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['image', 'title', 'category', 'status', 'description']
widgets = {
'image': …
}
Where you replace … with the widget you want to use for the image field.
Then you can plug in that form:
# app/views.py
from app.forms import PostForm
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
model = Post
form_class = PostForm
template_name = 'blog/post-form.html'
success_message = 'Your post has been updated.'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
def get_context_data(self, **kwargs):
context = super(PostUpdateView, self).get_context_data(**kwargs)
context['title'] = 'Update post'
context['submit'] = 'Update'
return context
def get_success_url(self):
author = self.object.author
return reverse_lazy( 'profile', kwargs={'author': author.username})
Behind the curtains, if you do not specify a form_class, Django will simply make one for you with the modelform_factory [Django-doc], so by using another ModelForm, we do not change the logic of using the form.

Django inline forms cannot query, must be model instance

I'm trying to make inline forms with class based views, i followed the instrunctions from here. The only change i've made was to give self.request.user instead of self.object to instance:
models.py
class Client(models.Model):
user = models.OneToOneField(CustomUser)
translate = models.BooleanField(default=False)
class ClientData(models.Model):
client = models.ForeignKey(Client)
language = models.ForeignKey(Language)
forms.py
class ClientForm(ModelForm):
class Meta:
model = Client
fields = '__all__'
exclude = ['user', ]
class ClientDataForm(ModelForm):
class Meta:
model = ClientData
fields = '__all__'
exclude = ['client', ]
ClientFormSet = inlineformset_factory(Client, ClientData, form=ClientDataForm, extra=1)
views.py
class ClientView(LoginRequiredMixin, UpdateView):
model = Client
fields = '__all__'
success_url = reverse_lazy('core:index')
class ClientDataView(LoginRequiredMixin, UpdateView):
template_name = 'core/client_data.html'
model = ClientData
form_class = ClientDataForm
success_url = reverse_lazy('core:index')
def get_object(self, queryset=None):
profile = get_object_or_404(ClientData, client__user=self.request.user)
return profile
def get_context_data(self, **kwargs):
context = super(ClientDataView, self).get_context_data(**kwargs)
if self.request.POST:
context['client_data'] = ClientFormSet(self.request.POST, instance=self.get_object())
else:
context['client_data'] = ClientFormSet(instance=self.get_object())
return context
def form_valid(self, form):
context = self.get_context_data()
client_data = context['client_data']
with transaction.atomic():
self.object = form.save()
if client_data.is_valid():
client_data.instance = self.object
return super(ClientDataView, self).form_valid(form)
Whenever i try to enter the page i get:
ValueError: Cannot query "asd#gmail.com": Must be "Client" instance.
[13/Dec/2017 15:48:36] "GET /client-data/ HTTP/1.1" 500 143759
for this line:
context['client_data'] = ClientFormSet(instance=self.get_object())
Your get_object is returning a ClientData instance.
def get_object(self, queryset=None):
profile = get_object_or_404(ClientData, client__user=self.request.user)
return profile
However, as the error suggests, the instance should be a Client instance, for example:
def get_object(self, queryset=None):
profile = get_object_or_404(Client, user=self.request.user)
return profile
Or you can simply follow the one-to-one relation backwards:
def get_object(self, queryset=None):
return self.request.user.client

Categories