django Multiple object mixins with get method - django

May be someone know, can i use Multiple object mixins with get method in my view? I understand that i need to specify queryset. But can i do this from method?
class Search(MultipleObjectMixin, View):
paginate_by = 2
def get(self, request, *args, **kwargs):
name = request.GET.get('name')
products = Product.objects.filter(name__contains=name)
self.queryset = products
category = Category.objects.all()
return render(request, 'search_results.html', {'main_list': products,
'category_list': category, 'name': name,
'matches': len(products)})

A better solution to what you are trying to accomplish is going to be to use a TemplateView or a ListView you are effectively not even using the MultipleObjectMixin in your example.
Here is an example with just a TemplateView without paging
class SearchView(TemplateView):
template_name = 'search_results.thml'
def get_context_data(self, **kwargs):
context = super(SearchView, self).get_context_data(**kwargs)
name = self.request.GET.get('name', '')
products = Product.objects.filter(name__contains=name)
context['main_list'] = products
context['category_list'] = Category.objects.all()
context['name'] = name
context['matches'] = products.count()
return context
Here is an example with a ListView, which I recommend since it uses the MultipleObjectMixin with it, but saves you some work.
class SearchView(ListView):
template_name = 'search_results.html'
model = Product
context_object_name = 'main_list'
def get_context_data(self, **kwargs):
context = super(SearchView, self).get_context_data(**kwargs)
context['category_list'] = Category.objects.all()
context['name'] = self.request.GET.get('name', '')
context['matches'] = self.get_queryset().count()
return context
def get_queryset(self):
qs = super(SearchView, self).get_queryset()
name = self.request.GET.get('name', '')
return qs.filter(name__contains=name)
You can even go a step further and create a CategoryMixin so you can inherit it in other views so you just add it in to get a list of categories
class CategoryMixin(object):
def get_context_data(self, **kwargs):
context['category_list'] = Category.objects.all()
return context
class SearchView(CategoryMixin, ListView):
template_name = 'search_results.html'
model = Product
context_object_name = 'main_list'
def get_context_data(self, **kwargs):
context = super(SearchView, self).get_context_data(**kwargs)
context['name'] = self.request.GET.get('name', '')
context['matches'] = self.get_queryset().count()
return context
def get_queryset(self):
qs = super(SearchView, self).get_queryset()
name = self.request.GET.get('name', '')
return qs.filter(name__contains=name)

Related

next or previous item within an ordered, filtered queryset in Django

How can I make transitions to the next article from the post_details(DetailView), so that both the next article and the previous one are available ?
vievs.py
class HomeView(ListView):
model = Post
#queryset = Post.objects.filter(status=1)
cats = Category.objects.all()
template_name = 'home.html'
#ordering = ['-post_date']
paginate_by = 6
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(HomeView, self).get_context_data(*args, **kwargs)
context["cat_menu"] = cat_menu
return context
class ArticleDetailView(HitCountDetailView):
model = Post
template_name = 'post_detail.html'
count_hit = True
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(ArticleDetailView, self).get_context_data(*args, **kwargs)
stuff = get_object_or_404(Post, id=self.kwargs['pk'])
total_likes = stuff.total_likes()
context["cat_menu"] = cat_menu
context["total_likes"] = total_likes
return context
Sort by date and ID
If you want the previous or next item based on a DateTimeField, you can work with .get_previous_by_fieldname(…) [Django-doc] or .get_next_by_fieldname(…) [Django-doc]. You thus can obtain the previous/next item for stuff with:
try:
prev_stuff = stuff.get_previous_by_post_date()
except Stuff.DoesNotExist:
prev_stuff = None
try:
next_stuff = stuff.get_next_by_post_date()
except Stuff.DoesNotExist:
next_stuff = None

How to pass a value from the view to a ModelForm

I'm trying to get the Id to filter items to show.
After several tutorials and docs, I'm still not get through...
Is it possible to do it ?
Here is the form:
class MakeChecklistDone(forms.ModelForm):
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
#title = forms.CharField(max_length = 32)
choices = forms.ModelMultipleChoiceField(
widget = forms.CheckboxSelectMultiple(),
queryset=CheckUpList.objects.all().filter(done=False, task=???)
)
class Meta:
model = CheckUpList
fields = ['choices', ]
I'm using the bellow view :
def task_detail(request, pk):
template_name = 'task/task-detail.html'
task = Task.objects.get(pk=pk)
...
if request.method == 'POST':
...
else:
form_checkUpList = MakeChecklistDone(request.POST, initial={'task': 11 })
But it seems I'm doing something wrong...
Any helps will be marvellous.
Instead of using a view function using a view class (Create view, update view, listing v) and use the get_form_kwargs method to pass a value to the form like below:
class task_detail(LoginRequiredMixin,
UpdateView):
template_name = 'learningcenters/lc/form.html'
form_class = LearningCenterForm
queryset = CheckUpList.objects.all()
def get_object(self):
id_ = self.kwargs.get("pk")
return get_object_or_404(task_detail, id=id_)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['task'] = 11
return kwargs
In form in init:
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
choices = forms.ModelMultipleChoiceField(
widget = forms.CheckboxSelectMultiple(),
queryset=CheckUpList.objects.all().filter(done=False, task=task)
)
ok, Thanks Salma. I made a confusion between "CBV" and "View function".
def task_detail(request, pk):
template_name = 'task/task-detail.html'
task = Task.objects.get(pk=pk)
..
if request.method == 'POST':
...
else:
form_checkUpList = MakeChecklistDone(task=task, request.POST)
For the form:
class MakeChecklistDone(forms.ModelForm):
choices = forms.ModelMultipleChoiceField(widget = forms.CheckboxSelectMultiple(), queryset=None)
class Meta:
model = CheckUpList
fields = ['choices', ]
def __init__(self, task, *args, **kwargs):
super(MakeChecklistDone, self).__init__(*args, **kwargs)
self.fields['choices'].queryset = CheckUpList.objects.all().filter(done=False, task=task))

How to pass Two templates in a same class based views

I am having one issue with the django template view.
I am having two urls
1) For Current User Profile
2) For His Team mates
urls.py
path('profile/', views.UserprofileIndex.as_view(), name='user-profile'),
path('profile/<int:pk>', views.TeamProfileIndex.as_view(), name='team-profile'),
It's views
class TeamProfileIndex(TemplateView):
template_name = 'accounts/profile/team_profile.html'
def get_context_data(self, **kwargs):
context = dict()
self.pk = self.kwargs.get("pk")
try:
user_profile = Profile.objects.get(user=self.pk)
except Profile.DoesNotExist:
logger.error("Requested user profile not available")
raise Http404
teams = User.objects.all()
context.update(
{
'user_profile': user_profile,
'teams' : teams
}
)
return context
class UserprofileIndex(TemplateView):
template_name = 'accounts/profile/index.html'
def get_context_data(self, **kwargs):
context = dict()
try:
user_profile = Profile.objects.get(user=self.request.user)
except Profile.DoesNotExist:
logger.error("Requested user profile not available")
raise Http404
teams = User.objects.all
context.update(
{
'user_profile': user_profile,
'teams' : teams
}
)
return context
In both views only one query is changing , that is 'user_profile'.
Is there any way to pass this in a single views to two diffrent html pages ?
I have tried following method
class UserprofileIndex(TemplateView):
# template_name = 'accounts/profile/index.html'
def initialize(self, *args, **kwargs):
self.pk = None
self.pk = kwargs.get('pk')
def get_template_names(self, *args, **kwargs):
if self.pk:
return 'accounts/profile/team_profile.html'
else:
return 'accounts/profile/index.html'
def get_context_data(self, **kwargs):
context = dict()
try:
if self.pk:
user_profile = UserProfile.objects.get(user=self.pk)
else:
user_profile = Profile.objects.get(user=self.request.user)
except Profile.DoesNotExist:
logger.error("Requested user profile not available")
raise Http404
teams = User.objects.all()
context.update(
{
'user_profile': user_profile,
'teams' : teams
}
)
return context
But its not working
This will work. But I would advise using DetailView
class UserProfile(TemplateView):
"""
User profile view
"""
user_profile = None
template_name = 'accounts/profile/index.html'
team_profile_template_name = 'accounts/profile/team_profile.html'
def get_user_profile(self):
"""
Get user
"""
if not self.user_profile:
user_profile_pk = self.kwargs.get('pk')
model, filter_kwargs = (UserProfile, dict(user=user_profile_pk)) \
if user_profile_pk else (Profile, dict(user=self.request.user))
self.user_profile = get_object_or_404(model, **filter_kwargs)
return self.user_profile
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(dict(user_profile=self.get_user_profile(),
teams=User.objects.all()))
return context
def get_template_names(self):
if self.kwargs.get('pk'):
return [self.team_profile_template_name]
return super().get_template_names()
If you want to use two template in signle class based view
Do something like this which i do for
DetailView
class PollDetail(DetailView):
model = Poll
context_object_name = "poll"
Instead mentioning template name in Class mention it in urls
ulrs.py
path("result/<pk>",PollDetail.as_view(template_name="results.html")),
path("vote/<pk>",PollDetail.as_view(template_name="vote.html"))

django search form to query only when form is submitted

Here is my view
class SingleNewsView(ListView):
model = News
form_class = SearchForm
template_name = "single_news.html"
def get(self, request, pk, **kwargs):
self.pk = pk
self.pub_from = request.GET.get('pub_date_from',False)
self.pub_to = request.GET.get('pub_date_to',False)
self.crawlers = request.GET.get('crawler',False)
print self.crawlers
return super(SingleNewsView,self).get(request,pk, **kwargs)
def get_context_data(self, **kwargs):
context = super(SingleNewsView,self).get_context_data(**kwargs)
context["form"] = SearchForm#(self.request.GET)
context["something"] = News.objects.filter(category_id=self.pk).filter(published_date__range=(self.pub_from,self.pub_to), crawler=self.crawlers)
return context
Here when I enter into the page it doesnot show any news because to data are not provided. I want all the news to be displayed initially and when the user submit the form then only filter work. How can I do that ??
You should add get_queryset() method than the doing filtering in get_context_data(). You can add the method as below
def get_queryset(self):
qs = News.objects.filter(category_id=self.pk)
#you can change this to just support one of the pub_from or pub_to
if self.pub_from and self.pub_to :
qs = qs.filter(published_date__range=(self.pub_from,self.pub_to)
if self.crawler:
qs = qs.filter(crawler=self.crawlers)

django form queryset filter by current user

I have made a search form like this where user can filter the news accroding to published date and the crawlers that they have selected previously.. Here is my form
class SearchForm(forms.Form):
pub_date_from = forms.CharField(label="From",max_length=20)
pub_date_to = forms.CharField(label="To",max_length=30)
crawler = forms.ModelMultipleChoiceField(label="Crawler",queryset=Crawler.objects.filter(created_by=self.request.user)
Here I want the crawler to be shown only the user have selected previously..
Here is my view..
class SingleNewsView(ListView):
model = News
form_class = SearchForm
template_name = "single_news.html"
# def post(self, request, **kwargs):
# print "request"
# form = SearchForm(request.user)
def get(self, request, pk, **kwargs):
#form = SearchForm(request.user)
self.pk = pk
self.pub_from = request.GET.get('pub_date_from',False)
self.pub_to = request.GET.get('pub_date_to',False)
self.crawlers = request.GET.get('crawler',False)
self.format = request.GET.get('format',False)
print self.format
print self.crawlers
return super(SingleNewsView,self).get(request,pk, **kwargs)
def get_context_data(self, **kwargs):
context = super(SingleNewsView,self).get_context_data(**kwargs)
context["form"] = SearchForm
if self.pub_from and self.pub_to and self.crawlers:
qs = News.objects.filter(category_id=self.pk).filter(published_date__range=(self.pub_from,self.pub_to), crawler=self.crawlers)
else:
qs = News.objects.filter(category_id=self.pk)
context["something"] = qs
self.request.session['something_pks'] = [ i.details for i in qs ]
return context
How can I get the current user in form and filter according to current user.. Need help
Just pass the user to form in view as keyword argument.
Just don't pass it on in form init method. Check out this post:
Passing **kwargs to Django Form
you hand over request.user just like user_details are passed into form in that example.
# Your best option is to declare the variable before `__init__`,
# and then set the variable to a form field inside `__init__`:
from django import forms
class MyForm(forms.Form):
location = None
def __init__(self, *args, **kwargs):
self.location = forms.ChoiceField(choices=Locations.objects.filter(user=kwargs.pop('user', None)))
super(MyForm, self).__init__(*args, **kwargs)
# In your class-based view pass self.request.user
# or in a function-based view pass request.user:
def MyView(request)
MyForm(user=request.user)