How to pass variable from view page to base template - python

I am trying to login the user into his profile and need to pass the username to a navbar in a base template.
I have base.html(base template) and index-client.html(body template).
Now from login view, i would like to pass username value to base.html.
Code after user authentication is:
if user is not None:
if user.is_active:
login(request, user)
return redirect('index-client.html')
I need to pass username to base.html i.e. a base template.

The {{ request.user }} method is built in with Django, and you can use this in any template to access the User object.
If you want to display the user's name in the navbar you can use:
{{ request.user.first_name|capfirst }} {{ request.user.last_name|capfirst }}
As can be seen this has the use of a template tag |capfirst to capitalise the first letter.

according to doc, redirect will accept
A model: the model’s get_absolute_url() function will be called.
A view name, possibly with arguments: reverse() will be used to reverse-resolve the name.
An absolute or relative URL, which will be used as-is for the redirect location.
So redirect to specific view which render the base html. In html
{% if request.user.is_authenticated %}
{{ request.user.username }}
{% endif %}

Related

Is it possible to add an input field to Wagtails custom bulk actions?

Is it possible to add an input field to Wagtails custom bulk actions?
In the template from the documentation example there is a block called form_section. Here I want to add a separate form to add another input field. Another position would be possible as well, of course.
<!-- /path/to/confirm_bulk_import.html -->
# ...
{% block form_section %}
{% if images %}
{% trans 'Yes, import' as action_button_text %}
{% trans "No, don't import" as no_action_button_text %}
# Can I use my own confirmation form here? How about its view?:
{% include 'wagtailadmin/bulk_actions/confirmation/form.html' with action_button_class="serious" %}
{% else %}
{% include 'wagtailadmin/bulk_actions/confirmation/go_back.html' %}
{% endif %}
{% endblock form_section %}
I would love to bulk select Image instances to add them to a Page. So I need to have a ChoiceField to select the Page. This would also require a customized View for the logic behind this "import". The latter is not the question. I am just wondering how I can add this input field and alter the view of a these marvelous bulk actions.
Standard bulk actions for images in Wagtail also include "Add images to collection":
The following is how the second step of this action looks like. I would love to add a custom bulk action in this sense to add images to a page (via a ImagePageRelation / InlinePanel)
Wagtail admin portal is using pure HTML and CSS. So everything coming to the python side is received via a HTML form. That means every button click in UI should associate with a HTML form and from wagtail side you can find it in the request.
Execute Action Method
If you went through the bulk action documentation, you will find that after the form is submitted, execute_action class method will be executed. Now you need to understand the parameters of this method.
#classmethod
def execute_action(cls, objects, **kwargs):
raise NotImplementedError("execute_action needs to be implemented")
As this is a class method, the first parameter is the class type which this method is on. You can learn more about class methods in the python documentation.
The 2nd parameter objects is the list of objects that you have selected for this bulk operation. To be precise, this is the list of objects that you have selected with the correct permission level. In the default implementation, permission is given for all the objects. But you can override this behavior.
def check_perm(self, obj):
return True
You can override this method in your custom bulk action class and check permission for each object. As the objects parameter, you will receive the only objects which have check_perm(obj)==True, from the list of objects you selected.
The 3rd parameter of execute_action class method is a keyworded argument list (a dictionary to be precise). This dictionary is obtained by calling the following method.
def get_execution_context(self):
return {}
Default behavior of this method is to return empty dictionary. But you can override this to send anything. Because execute_action is a class method, it can't access the instant variables. So this method is very helpful to pass instance variables to execute_action class method.
Lets look at an example.
#hooks.register('register_bulk_action')
class CustomBulkAction(ImageBulkAction):
display_name = _("A Thing")
aria_label = _("A thing to do")
action_type = "thing"
template_name = "appname/bulk/something.html"
def get_execution_context(self):
print(self.request)
return super().get_execution_context()
If you run this example, you can see the data submitted from the HTML form.
<WSGIRequest: POST '/admin/bulk/image/customimage/thing/?next=%2Fadmin%2Fimages%2F&id=1'>
Override the HTML Form
In the bulk action template, you can't find any HTML <form></form> tag. It is because the form with action buttons are in wagtailadmin/bulk_actions/confirmation/form.html file that you have import in the template. You can create the copy of that file and change it's behavior.
<form action="{{ submit_url }}" method="POST">
{% include 'wagtailadmin/shared/non_field_errors.html' %}
{% csrf_token %}
{% block form_fields %}
<!-- Custom Fields goes here -->
{% endblock form_fields %}
<input type="submit" value="{{ action_button_text }}" class="button {{ action_button_class }}" />
{{ no_action_button_text }}
</form>
You can add custom fields you need in the area that I mentioned above sample code and values of those additional fields will be there in self.request.POST parameter. This is the easiest way to get something from the template to python side.
Django Forms
But that is not the best way. Django recommends using forms for these purposes. You can find more about Django forms in the documentation.
Almost every place that there is a form in a wagtail template, there is a associated Django form. In this case, the instance variable form_class is used to associate a bulk action template with a Django form.
class MyForm(forms.Form):
extra_field = forms.CharField(
max_length=100,
required=True,
)
#hooks.register('register_bulk_action')
class CustomBulkAction(ImageBulkAction):
display_name = _("A Thing")
aria_label = _("A thing to do")
action_type = "thing"
template_name = "appname/bulk/something.html"
form_class = MyForm
def get_execution_context(self):
print(self.cleaned_form.data)
return super().get_execution_context()
And very simply, I will add all the form fields to the template as in the below sample code.
<form action="{{ submit_url }}" method="POST">
{% include 'wagtailadmin/shared/non_field_errors.html' %}
{% csrf_token %}
{% block form_fields %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.label_tag }} {{ field }}
{{ field.errors }}
</div>
{% endfor %}
{% endblock form_fields %}
<input type="submit" value="{{ action_button_text }}" class="button {{ action_button_class }}" />
{{ no_action_button_text }}
</form>
Now this will print the data received from the HTML form. What we need to do is to pass the form data as kwargs to the execute_action class method.
Final Example
#hooks.register('register_bulk_action')
class CustomBulkAction(ImageBulkAction):
display_name = _("A Thing")
aria_label = _("A thing to do")
action_type = "thing"
template_name = "appname/bulk/something.html"
form_class = MyForm
def get_execution_context(self):
data = super().get_execution_context()
data['form'] = self.cleaned_form
return data
#classmethod
def execute_action(cls, objects, **kwargs):
print("KWARGS:", kwargs)
print(kwargs['form'].cleaned_data['extra_field'])
# Do what you want
return 0, 0
I believe this was helpful and answered all the questions related to bulk action submission.
With forms.ModelChoiceField in your form, you can get values from Django Models and pass them to the HTML field. You have to pass a queryset in the constructor.
extra_field = forms.ModelChoiceField(
required=True,
queryset=Collection.objects.order_by("name"),
)

Django passing data from one app to another?

I am using django-allauth for my authentication. I have a dashboard which has many links.
user.html
`{% include 'sidebar.html' %}
<h1>Profile View</h1>
<p>{{ profile.username }}</p>`
change_password.html
`{% include 'sidebar.html' %}
<h2>Change Password</h2>
<p>{{ profile.username }}</p>`
sidebar.html
`Profile View
Change Password`
views.py
class ProfileView(DetailView):
template_name = "user.html"
queryset = User.objects.all()
context_object_name = 'profile'
slug_field = "username"
change password view is from django-allauth. How can i pass the the username from the ProfileView to the change password view so that i can display in the change_password.html page.
Main Problem
Since i have been including sidebar.html to both the views, it works good in ProfileView but when i navigate to change_password view i get the following error
Reverse for 'profile_view' with keyword arguments '{'slug': ''}' not found. 1 pattern(s) tried: ['(?P[-\w.#+-]+)/$']
the error does not show in ProfileView because the profile.username returns a value, but when i navigate to change_password view i get the above error because the profile context object only passes in that particular view. i want to use that context_object through out the project.
Is there a simple way to do it? other than build a JSON API?
I just had a quick look at the template tags provided by the allauth app. I haven't tested this (nor do I use the project) but this looks like what you are looking for.
In your template, any template...
{% load account %} {# this should be near the top with any other load tags #}
{# this can be anywhere in the template. I'm not positive what it returns but it looks like it is the username. #}
<p>
{% user_display user %}
</p>
I found the answer here.
I got it working, Thank you #teewuane
sidebar.html
Profile View
replaced as
Profile View

Using #processor_for with a Form in Mezzanine

I've built a Form Page in the admin of my Mezzanine project, but I'd like to populate a couple of the fields automatically, depending on where the click to the form has come from: it's a "feedback" form and I'd like to automatically add the ID of the object that the user is providing feedback on to a hidden field in the form.
I've copied the template code from mezzanine/forms/templates/pages/form.html to a custom template and it receives the dictionary I pass it from my view, but I can't work out to pass it my the form I want rendered. The #processor_for function receives request and page... but where's the form?
What should I be passing to my template to render the form?
You can use the template tag fields_for:
{% load mezzanine_tags %}
{% errors_for some_form_object %}
<form method="POST">
{% fields_for some_form_object %}
<input type="submit">
</form>

Adding start separate page in django app

I want to add a separate homepage in my Django app.
If a user is logged in to show him all the content.
If the user is not logged in to show him the starting page and a link to login.
The solution is based on the code below does not always pass the exam.
{% if user.is_authenticated %}
//Something
{% else %}
//Something
{% endif %}
My view:
class Start(TemplateView):
template_name = "dashboard/start.html"
You can override the get_template_names() method of the view and render different templates for anonymous and logged users:
class Start(TemplateView):
def get_template_names(self):
if self.request.user.is_authenticated():
return ['dashboard/dashboard.html']
return ['dashboard/start.html']

user auth template tags not working-Django

I used django-registration app. Everything goes fine. User gets registered with email verification but when user logs in and is redirected to mainpage the auth template tags such as {% if user.is_authenticated %} returns false.
I am having this in my login.html
<input type="hidden" name="next" value="/" />
After login I want to redirect the user to main page and in mainpage.html
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
but user.is_authenticated returns false here. What might be the problem here? Thanks
Try using {% if request.user.is_authenticated %} instead. It's entirely possible that user isn't being passed into the context dictionary within the view. If the object is not found within the template, it will just skip to the else portion of the block. Rendering templates are strange in django, as what would normally be an exception, is swallowed.
Can you show us the code for the view which handles the URL '/'? I think this is where your problem lies, rather than in your use of django-registration.
Does this view put user in the context? If you want to use it in the template, you're going to have to put it in. If you want to use request in the context, then you need to make sure that you pass an instance of RequestContext as the context rather than just a standard context object.
Here's what worked for me.
Suppose your main page gets processed by a view in views.py
from django.shortcuts import render_to_response
def mainpage(request):
return render_to_response('mainpage.html')
You need to add RequestContext to include to user object. Change your view to
from django.shortcuts import render_to_response
from django.template import RequestContext
def mainpage(request):
return render_to_response('mainpage.html', context_instance=RequestContext(request))

Categories

Resources