How to pass Two templates in a same class based views - django

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"))

Related

request not defined inside forms.py class (forms.Form)

The error
NameError: name 'request' is not defined
My forms.py
class PersonForm(forms.Form):
name = forms.CharField(required=False)
job_title = forms.CharField(required=False)
status = forms.TypedChoiceField(choices=Person.STATUS_CHOICES)
project = Project.objects.get(users=request.user, pk=self.kwargs.get('pk'))
company = forms.ModelChoiceField(queryset=project.companies.all(),required=False)
new_company = forms.CharField(required=False)
note = forms.CharField(required=False)
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
def clean(self):
return self.cleaned_data
views.py
class PersonCreate(LoginRequiredMixin, FormView):
template_name = 'person/person_form.html'
form_class = PersonForm
success_url = '/project/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
cleaned_data = form.clean()
active_project = self.request.session['active_project']
project = Project.objects.get(users=self.request.user, pk=self.request.session['active_project'])
if cleaned_data['name']:
person, created = Person.objects.get_or_create(
name=cleaned_data['name'],
job_title=cleaned_data['job_title'],
created_by=self.request.user,
status=cleaned_data['status'],
project=project
)
if cleaned_data['new_company']:
company, created = Company.objects.get_or_create(name=cleaned_data['new_company'], project=project, created_by=self.request.user)
company.persons.add(person)
company.save()
if cleaned_data['note']:
person.note_set.create(content=cleaned_data['note'], created_by=self.request.user)
person.save()
if cleaned_data['company']:
company = project.companies.get(name=cleaned_data['company'])
company.persons.add(person)
company.save()
return super().form_valid(form)
def get_success_url(self):
return self.request.POST.get('next', '/project/' + str(self.request.session['active_project']))
I want to filter the queryset on the forms.ModelChoiceField field company. Based on the companies of the project the user has access to. How would I do that? Can I access request.session data as well here?
You can't do that like this, because Django forms don't have access to the request at all.
So the best approach I can think of is to pass the user to the form and then use the data when initialized.
First you have to pass the user and pk in the view.
views.py:
# ...
form = PersonForm(user=request.user, pk=kwargs.get('pk'))
Then in your form, you can catch both kwargs and update the project with the correct value,
class PersonForm(forms.Form):
# your form fields code ...
def __init__(self, *args, **kwargs):
# get the user and pk
user = kwargs.pop('user', None)
pk = kwargs.pop('pk', None)
# update project field
super(PersonForm, self).__init__(*args, **kwargs)
self.fields['project'] = Project.objects.get(users=user, pk=pk)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
In class-based views to update Form kwargs:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({"request": self.request})
return kwargs

NOT NULL constraint failed when save ModelForm

I am new in Django (1.9)
I have a NOT NULL constraint failed when I save my ModelForm and i don't understand why ...
I propose to the user a form to post a comment and the only field include in the form is "text", i want to set the excluded fields in my view after the validation and before save in database
Models.py :
class Commentaire(models.Model):
text = RichTextField()
pub_date = models.DateTimeField()
author = models.ForeignKey(User)
post = models.ForeignKey(Post)
publish = models.BooleanField()
def __str__(self):
return "/%s/%s" % (self.pub_date,self.author.username)
class Meta:
ordering = ["-pub_date"]
Forms.py :
class CommentaireForm(forms.ModelForm):
class Meta:
model = Commentaire
fields = ['text']
Views.py :
class PostDetail(View):
def get(self, request, *args, **kwargs):
view = PostDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostComment.as_view()
return view(request, *args, **kwargs)
class PostDisplay(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDisplay, self).get_context_data(**kwargs)
context['form'] = CommentaireForm()
return context
class PostComment(SingleObjectMixin, FormView):
template_name = 'blogengine/post_detail.html'
form_class = CommentaireForm
model = Post
def post(self, request, *args, **kwargs):
#if not request.user.is_authenticated():
# return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
form.save(commit=False)
form.post = self.object
form.author = self.request.user
form.pub_date = datetime.now()
form.publish = True
form.save()
return HttpResponseRedirect(self.get_success_url())
When Django save the form, i have this exception :
NOT NULL constraint failed: blogengine_commentaire.pub_date
The values i set for the excluded fields (author, post, pub_date) in "form_valid" are not taken into account, they seem to stay NULL
Could you explain me why because i am lost ?
Thanks
You need to rewrite form_valid method like that
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
model_instance = form.save(commit=False)
model_instance.post = self.object
model_instance.author = self.request.user
model_instance.pub_date = datetime.now()
model_instance.publish = True
model_instance.save()
return HttpResponseRedirect(self.get_success_url())
Because save(commit=False) will return you an Post instance that you then need to populate and save.

django Multiple object mixins with get method

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)

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)

how to get initial parameters during updating a form in Django with TemplateView

I have the following class based TemplateView, I want my TemplateView to be like UpdateView.But I am not very sure where to set the form with the instance parameters.
I try it in get_context_data but didn't work. Any ideas ?
class ProfileUpdateView(generic.TemplateView):
template_name = "profile/update_profile.html"
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated():
return super(ProfileUpdateView, self).dispatch(*args, **kwargs)
else:
return HttpResponseRedirect('/profiles/login')
def get_context_data(self, *args, **kwargs):
context = {}
try:
Profile.objects.get(user__id=self.request.user.id)
user = Profile.objects.get(user__id=self.request.user.id)
context['profile_form'] = profile_form(data=request.POST, instance=user)
except:
context['profile_form'] = ProfileForm(data=self.request.POST)
context['profile'] = Profile.objects.filter(user=self.request.user.id)
context['experiences'] = Experience.objects.filter(user=self.request.user.id)
context['education'] = Education.objects.filter(user=self.request.user.id)
context['award'] = Award.objects.filter(user=self.request.user.id)
context['publication'] = Publication.objects.filter(user=self.request.user.id)
context['membership'] = Membership.objects.filter(user=self.request.user.id)
context['patent'] = Patent.objects.filter(user=self.request.user.id)
context['certificate'] = Certificate.objects.filter(user=self.request.user.id)
context['language'] = Language.objects.filter(user=self.request.user.id)
return context
def post(self, request, *args, **kwargs):
if self.request.POST:
profile_form = ProfileForm(data=request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = request.user
profile.save()
return HttpResponseRedirect('/')
Try use CBV(CreateView), and then use initial and def get_initial(self):
See this link, I think this can help you. Section 9-11 and 9-12.