python - django extra_context wont show - python

I have a form in ListView view using FormMixin that form takes a string lastname
and querys to take a queryset of Account object, I want that Queryset on my template via extra_context.
The form works and I have the queryset that I want, I pass it into self.extra_context and I can see it on console with print BUT it doesn't show in my template. Im feeling stacked, please help me if tou can.
class DepartmentFilesListView(LoginRequiredMixin, SelectRelatedMixin,FormMixin, ListView):
model = FileDetail
login_url = '/'
template_name = 'incomingfiles/departmentFileList_All.html'
context_object_name = 'departmentFiles'
form_class = ChooseOperatorForm
success_url = reverse_lazy('incomingfiles:DepartmentFilesListView')
def __init__(self):
super(DepartmentFilesListView, self).__init__()
now = timezone.now()
self.extra_context = {'title':'Έγγραφα Τμήματος','date':now.date(), 'day':getDay(now.weekday())}
def dispatch(self, request, *args, **kwargs):
return super(DepartmentFilesListView, self).dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# for
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
lastname = form.cleaned_data['lastname']
lastname = valuateLastname(lastname)
self.extra_context['operators'] = Account.objects.filter(
is_active=True,
department=self.request.user.department,
last_name__contains=lastname
)
print(self.extra_context['operators'])
return super(DepartmentFilesListView, self).form_valid(form)
def form_invalid(self, form):
return super(DepartmentFilesListView, self).form_invalid(form)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
context['filter_for_all'] = FileDetailFilter(self.request.GET, queryset=self.get_queryset())
num_in_page = 50
paginated_filter_for_all = Paginator(context['filter_for_all'].qs, num_in_page)
filter_for_all_page_number = self.request.GET.get('page')
filter_for_all_page_obj = paginated_filter_for_all.get_page(filter_for_all_page_number)
context['filter_context_obj'] = filter_for_all_page_obj
return context
def get_queryset(self):
self.department = self.request.user.department
return FileDetail.objects.filter(Q(Q(apantitiko__operator__department=self.department)
| Q(departmentassignment__department=self.department)))
And this is the sample of my template
<div class="col-12 Search-operator-div">
<div class="row">
<h2>Αναζήτηση χρεωμένων εγγράφων κατα χειριστή</h2>
</div>
<div class="row" style="width:100%; border-top: 2px solid #212529;"></div>
<br>
<form id="exactΟperator" method="post">
{% csrf_token %}
<div class="row">
{% for field in form %}
<div class="col-1 align-self-center">
<label id="id_{{ field.name }}_label">{{ field.label }}</label>
</div>
<div class="col-3 align-self-center">
{{ field }}
{{ field.error }}
<a role="button" id="cancelOperator" type="button">
<i class="fas fa-times"></i></a>
</div>
{% endfor %}
<div class="col-1 align-self-center">
<input id="SearchOperator" type="submit" value="Αναζήτηση" class="btn btn-primary btn-sm">
</div>
</div>
</form>
<div class="row search-operator-div-content">
{% for operator in operators %}
<div class="col">
<a href="{% url 'incomingfiles:OperatorFilesListView' pk=operator.pk %}" class="link-transition btn-link">
{{ operator }}</a>
</div>
{% endfor %}
</div>
<br>
</div>
In my template I can see anything else is in my self.extra_context but anything Im tried to pass in my form_valid function doesn't shown.
It is like my extra_context cant update in this function.

The default implementation for form_valid() simply redirects to the success_url.
So it returns:
return HttpResponseRedirect(self.get_success_url())
And calling extra_context_data is skipped.
SOLUTION
Return HttpResponse instead super(DepartmentFilesListView, self).form_valid(form):
def form_valid(self, form):
lastname = form.cleaned_data['lastname']
lastname = valuateLastname(lastname)
self.extra_context['operators'] = Account.objects.filter(
is_active=True,
department=self.request.user.department,
last_name__contains=lastname
)
print(self.extra_context['operators'])
return render(self.request, self.template_name, self.get_context_data())

I think this is the easiest method:
class SomeListView(ListView):
.....
extra_context = self.myquery()
.....
def myquery(self):
return { 'query': QuerySet}
Then in template
{{query}}

Well I found a solution but I don't know if that's the correct way to solve that problem.
If you have anything to suggest it will be my pleasure to try it.
To solve my problem I pass the lastname value into the session and query in get_context_data .
def form_valid(self, form):
lastname = form.cleaned_data['lastname']
lastname = valuateLastname(lastname)
if lastname == '':
lastname = '-'
elif lastname == '*':
lastname = ''
self.request.session['lastname'] = lastname
# print(self.extra_context['operators'])
return super(DepartmentFilesListView, self).form_valid(form)
def form_invalid(self, form):
print(self.extra_context['operators'])
return super(DepartmentFilesListView, self).form_invalid(form)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
context['filter_for_all'] = FileDetailFilter(self.request.GET, queryset=self.get_queryset())
num_in_page = 50
paginated_filter_for_all = Paginator(context['filter_for_all'].qs, num_in_page)
filter_for_all_page_number = self.request.GET.get('page')
filter_for_all_page_obj = paginated_filter_for_all.get_page(filter_for_all_page_number)
context['operators'] = Account.objects.filter(is_active=True,
department=self.request.user.department,
last_name__contains=self.request.session['lastname'])
context['filter_context_obj'] = filter_for_all_page_obj
return context

Related

The form for UpdateView for editing the user profile is not displayed. Django

I'm trying to make an UpdateView to edit user profile without pk or slug using get_object() with self.request.user. But when I run my settings, the form is not shown. Here is my code:
urls.py:
urlpatterns = [
path('settings/', UserSettings.as_view(), name='settings'),
path('<slug:profile_slug>/', ShowUserProfile.as_view(), name='profile'),
]
views.py:
class UserSettings(LoginRequiredMixin, DataMixin, UpdateView):
template_name = 'users/user_settings.html'
form_class = UpdateUserForm
def get_object(self, *args, **kwargs):
return self.request.user
def get_success_url(self):
return reverse_lazy('profile', kwargs={'profile_slug': self.request.user.userpofile.slug})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
c_def = self.get_user_context(title='Settings')
forms.py:
class UpdateUserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'password')
widgets = {'username': forms.TextInput(attrs={'class': 'form-control form-input form__input'}),
'password': forms.TextInput(attrs={'class': 'form-control form-input form__input'})}
user_settings.html:
<form class="form" method="post">
{% csrf_token %}
{% for item in form %}
<div class="row">
<div class="col-sm-4">
<label class="form__label" for="{{item.id_for_label}}">{{item.label}}: </label>
</div>
<div class="col-sm-8">
{{item}}
</div>
</div>
<div class="form__errors">{{item.errors}}</div>
{% endfor %}
<button class="button" type="submit">Set settings</button>
</form>
It doesn't even throw an error. What I need to do?
You need to return you get_context_data function, like so:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
c_def = self.get_user_context(title='Settings')
return context

get_absolute_url not making any effect

I only used this in my template. I am following a tutorial. In tutorial video is working but I couldn't make it work. Here is my template code:
<i> {% for object in object_list %}
<div class="media">
<div class="media-left">
<a href="#">
{% if object.img %} <img class="media-object" src="..." alt="...">
{% endif %}
</a>
</div>
<div class="media-body">
{{ object.content }}<br/>
via {{ object.user }} | {{ object.timestamp|timesince }} ago |
<a href='{{ object.get_absolute_url }}'>View</a>
</div>
</div>
<hr/> </i>
My views.py
<i>
Create your views here.
class TweetCreateView(FormUserNeededMixin, CreateView):
form_class = TweetModelForm
template_name = 'tweets/create_view.html'
class TweetUpdateView(LoginRequiredMixin, UserOwnerMixin, UpdateView):
form_class = TweetModelForm
queryset = Tweet.objects.all()
template_name = 'tweets/update_view.html'
success_url = '/tweets/'
class TweetDeleteView(LoginRequiredMixin, DeleteView):
model = Tweet
template_name = 'tweets/delete_confirm.html'
success_url = reverse_lazy('tweets:home')
class TweetDetailView(DetailView):
template_name = "tweets/detail_view.html"
queryset = Tweet.objects.all()
def get_object(self):
print(self.kwargs)
pk = self.kwargs.get("pk")
print(pk)
return Tweet.objects.get(id=pk)
class TweetListView(ListView):
template_name = "tweets/tweets_list.html"
def get_queryset(self, *args, **kwargs):
qs = Tweet.objects.all()
print(self.request.GET)
query = self.request.GET.get("q", None)
if query is not None:
qs = qs.filter(Q(content=query))
return qs
def get_context_data(self, *args, **kwargs):
context = super(TweetListView, self).get_context_data(*args, **kwargs)
context['create_form'] = TweetModelForm()
context['create_url'] = reverse_lazy('tweets:create')
return context
</i>
my models.py
<i>
class Tweet(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, )
content = models.CharField(max_length=140, validators=[ validate_content ])
updated = models.DateField(auto_now=True, )
timestamp = models.DateField(auto_now_add=True, )
def __str__(self):
return str(self.content)
</i>
You have to add methode get_absolute_url to your models, it's should look like that :
def get_absolute_url(self):
from django.urls import reverse
return reverse('tweets:detail', kwargs={
'pk': self.pk
})

Best way to fetch and display request parameters in generic CreateView

I have a model
class MyModel(models.Model):
slug = models.UUIDField(default=uuid4, blank=True, editable=False)
advertiser = models.ForeignKey(Advertiser)
position = models.SmallIntegerField(choices=POSITION_CHOICES)
share_type = models.CharField(max_length=80)
country = CountryField(countries=MyCountries, default='DE')
# some other Fields. Edited in a ModelForm
This view is called by a url containg position, share_type, country as parameters. I would like to display these parameters in the template. What is the best way to do this. I already have these possibilies
1) use get_context_date and store this in the context
def get_context_data(self, **kwargs):
ctx = super(MyModel, self).get_context_data(**kwargs)
ctx['share_type'] = self.kwargs.get('share_type', None)
ctx['country'] = self.kwargs.get('country', None)
ctx['postal_code'] = self.kwargs.get('postal_code', None)
ctx['position'] = int(self.kwargs.get('position', None))
return ctx
This can then be used in the template
2) use the view variant
def share_type(self):
ret = self.kwargs.get('share_type', None)
return ret
def country(self):
ret = self.kwargs.get('country', None)
return ret
like
<div class="row">
<strong>
<div class="col-sm-3">
Type : {{ view.share_type }}
<div class="col-sm-3">
Country : {{ view.country }}
I think both way are somewhat redundant. Does anybody know a more generic approach to this.
Kind regards
Michael
I think the best way is to do it like this :
def dispatch(self, request, *args, **kwargs):
self.share_type = self.kwargs.get('share_type', None)
self.country = self.kwargs.get('country', None)
self.postal_code = self.kwargs.get('postal_code', None)
self.position = int(self.kwargs.get('position', None))
self.position_verbose = verbose_position(self.position)
ret = super(CreateAdvertisment, self).dispatch(request, *args, **kwargs)
return ret
You can use then in the form_valid method
def form_valid(self, form):
form.instance.advertiser = self.advertiser
form.instance.share_type = self.share_type
form.instance.country = self.country
form.instance.postal_code = self.postal_code
form.instance.position = self.position
ret = super(CreateAdvertisment, self).form_valid(form)
return ret
and in the template of course like this
<strong>
<div class="col-sm-3">
Typ : {{ view.share_type }}
</div>
<div class="col-sm-3">
PLZ : {{ view.postal_code }}
</div>
<div class="col-sm-3">
Ort : TODO
</div>
<div class="col-sm-3">
Pos : {{ view.position_verbose }}
</div>
Many thanks for the proposals.
Regards
Michael

Django Crispy Forms with custom field template is not adding the value of the field to request

I am using Django 1.10 and django-crispy-forms 1.6.1 in my project. I added a custom datetimepicker dropdown template that seems to be functioning correctly. The problem I am now encountering, is that every time I attempt to submit a form, I am flashed with the error on the field that it is required. It seems that after submitting the form, the field is cleared out, and the error class is added to the field.
After submit, form shows errors
When I checked the console, I receive no errors, but when I check Chrome DevTools, I looked at the request payload sent server-side and I see that the field is not added at all to the request. Here is a picture of the request payload from the dev tools.
DevTools request payload without "time_stamp"
I am able to get the datetimepicker to dropdown when the input receives focus, and that seems to work just fine. Here is the relevant code for my forms/views, and the custom template.html:
models.py
class Call(models.Model):
history = AuditlogHistoryField()
analyst = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, blank=True, null=True, limit_choices_to={'is_staff': True}, related_name='call_analyst')
contact = models.CharField(max_length=50)
time_stamp = models.DateTimeField(default=datetime.now)
description = models.CharField(max_length=512)
ticket = models.PositiveIntegerField(blank=True, null=True)
CALL_TYPE = (
('M', 'Made'),
('R', 'Received'),
)
call_type = models.CharField(max_length=1, choices=CALL_TYPE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
#python_2_unicode_compatible
def __str__(self):
return "Call instance {}".format(self.pk)
forms.py
class CallForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea)
class Meta:
model = Call
fields = ['analyst', 'contact', 'time_stamp', 'description', 'ticket', 'call_type']
def __init__(self, *args, **kwargs):
super(CallForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_tag = True
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-3'
self.helper.field_class = 'col-sm-9'
self.helper.layout = Layout(
Field('analyst'),
Field('contact'),
Field('time_stamp', template="datetimepicker.html"),
Field('description'),
Field('ticket'),
Field('call_type'),
)
def is_valid(self):
return super(CallForm, self).is_valid()
def full_clean(self):
return super(CallForm, self).full_clean()
def clean_analyst(self):
analyst = self.cleaned_data.get("analyst", None)
return analyst
def clean_contact(self):
contact = self.cleaned_data.get("contact", None)
return contact
def clean_time_stamp(self):
time_stamp = self.cleaned_data.get("time_stamp", None)
return time_stamp
def clean_description(self):
description = self.cleaned_data.get("description", None)
return description
def clean_ticket(self):
ticket = self.cleaned_data.get("ticket", None)
return ticket
def clean_call_type(self):
call_type = self.cleaned_data.get("call_type", None)
return call_type
def clean(self):
return super(CallForm, self).clean()
def validate_unique(self):
return super(CallForm, self).validate_unique()
def save(self, commit=True):
return super(CallForm, self).save(commit)
views.py
class CallCreateView(AjaxCreateView):
model = Call
form_class = CallForm
# fields = ['analyst', 'contact', 'call_timestamp', 'description', 'ticket', 'call_type']
template_name = "reports/../_templates/create_update_template.html"
success_url = reverse_lazy("call_list")
def __init__(self, **kwargs):
super(CallCreateView, self).__init__(**kwargs)
def dispatch(self, request, *args, **kwargs):
return super(CallCreateView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return super(CallCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super(CallCreateView, self).post(request, *args, **kwargs)
def get_form_class(self):
return super(CallCreateView, self).get_form_class()
def get_form(self, form_class=None):
return super(CallCreateView, self).get_form(form_class)
def get_form_kwargs(self, **kwargs):
return super(CallCreateView, self).get_form_kwargs()
def get_initial(self):
return super(CallCreateView, self).get_initial()
def form_invalid(self, form):
return super(CallCreateView, self).form_invalid(form)
def form_valid(self, form):
obj = form.save(commit=False)
obj.save()
return super(CallCreateView, self).form_valid(form)
def get_context_data(self, **kwargs):
ret = super(CallCreateView, self).get_context_data(**kwargs)
return ret
def render_to_response(self, context, **response_kwargs):
return super(CallCreateView, self).render_to_response(context, **response_kwargs)
def get_template_names(self):
return super(CallCreateView, self).get_template_names()
def get_success_url(self):
return reverse("call_detail", args=(self.object.pk,))
datetimepicker.html
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %}
class="form-group{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}"
class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
<div class="controls date datetimepicker col-sm-9" id="{{ field.id_for_label }}"
data-link-field="{{ field.id_for_label }}" {{ flat_attrs|safe }}>
<input class="form-control" id="{{ field.id_for_label }}" type="text">
</div>
<input type="hidden" id="{{ field.id_for_label }}" value=""/><br/>
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
{% block datetimepicker %}
<script type="text/javascript">
$(function () {
$('#{{ field.id_for_label }}').datetimepicker({
sideBySide: true,
allowInputToggle: true,
showTodayButton: true,
showClear: true,
showClose: true,
toolbarPlacement: "top",
format: "dddd, MMMM Do YYYY, h:mm A"
})
})
</script>
{% endblock %}
I think there must be a problem either with my template, or how django-crispy-forms handles fields that use a custom template, because when I remove the template from the form helper, a regular input box is used and the datetime string is submitted just fine to django. Thank you all for your help. Sorry that I had to link the images, I don't have a high enough rep to embed them.
I think the reason why the time_stamp is not being sent to the server because the datepicker input tag doesn't have a name attribute:
<input class="form-control" id="{{ field.id_for_label }}" type="text">
Have a look at the notes in w3schools:
Note: Only form elements with a name attribute will have their values passed when submitting a form.

django generic view gives HTTP 405 error while generating reports and tables

I wish to to develop a small class based view that generates reports in table form using django filters and django tables2.
I am following this guide.
http://www.craigderington.me/django-generic-listview-with-django-filters-and-django-tables2/
My code is generating the table as well filtering it but when i click on the search button, It gives a HTTP 405 error in the terminal and displays a blank page. Here is my code. How do i fix it to make it work?
IssueListView Class
class IssueListView(PagedFilteredTableView):
model = Issue
template_name = 'issue_list.html'
context_object_name = 'issue_list'
ordering = ['id']
table_class = IssueTable
filter_class = IssueFilter
formhelper_class = IssueListFormHelper
def get_queryset(self):
qs = super(IssueListView,
self).get_queryset()
return qs
def post(self,request,*args,**kwargs):
return PagedFilteredTableView.as_view()(request)
def get_context_data(self,**kwargs):
context = super(IssueListView,
self).get_context_data(**kwargs)
search_query = self.get_queryset()
table = IssueTable(search_query)
RequestConfig(self.request,paginate={'per_page':30}).configure(table)
context['table'] = table
return context
PagedFilteredTableView class
class PagedFilteredTableView(SingleTableView):
filter_class = None
formhelper_class = None
context_filter_name = 'filter'
def get_queryset(self,**kwargs):
qs = super(PagedFilteredTableView,
self).get_queryset()
self.filter = self.filter_class(self.request.GET,queryset=qs)
self.filter.form.helper = self.formhelper_class()
return self.filter.qs
def get_context_data(self,**kwargs):
context = super(PagedFilteredTableView,
self).get_context_data()
context[self.context_filter_name] = self.filter
return context
The template has the following form which contains the POST method to search the displayed table/report
<form method="post" class="form-inline form-search pull-right ">
{% csrf_token %}
<div>
<input id="search_form_id" name="search" type="text" class="form-control col-md-3" placeholder="ID, Name, Account #, ZIP"{% if search %} value="{{ search }}"{% endif %}>
<button type="submit" class="btn btn-small btn-dark"><i class="fa fa-search"></i> Search</button>
</div>
</form>
Urls.py contains the following line
url(r'^$',views.IssueListView.as_view(),name = 'index'),

Categories