Passing context value to profile signup template in django-allauth - django

With django-allauth, I am forcing a new user to fill out additional profile information on signup using a custom ACCOUNT_SIGNUP_FORM.
settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'profiles.signup.ProfileSignupForm'
SOCIALACCOUNT_AUTO_SIGNUP = False
This ProfileSignupForm is then rendered in a modified allauth/templates/socialaccount/signup.html template. This modified template renders the logo of the new user's company that is defined in the new user's session (I used an invitation link that first goes to a RedirectView, writes into the session, and then forwards to the new signup).
signup.html
<html>
<body>
<img src="{{ logo }}" />
{% crispy form %}
</body>
</html>
How can I pull the company logo from my session and pass it to my template without forking the repository and modifying the SignUp View?
That approach would look like this:
class SignupView(RedirectAuthenticatedUserMixin, CloseableSignupMixin, FormView):
def dispatch(self, request, *args, **kwargs):
...
self.company = request.session.get('company')
...
def get_context_data(self, **kwargs):
...
context['logo'] = company.logo
...

Either you can follow the above mentioned way to Inherit the View and Define custom url for Signup to use your view.
Or
you car directly access company logo in your template as:
{{ request.session.company.logo }}
This can be done because request is available as a context variable in Templates if rendered with RequestContext instance.

you can inherit SignupView directly in your code instead of forking and modifying the original SignupView.
class MySignupView(SignupView):
def dispatch(self, request, *args, **kwargs):
...
self.company = request.session.get('company')
...
return super(MySignupView, self).dispatch(request, *args, *kwargs)
def get_context_data(self, **kwargs):
context = super(MySignupView, self).get_context_data(**kwargs)
context['logo'] = self.company.logo
return context
Then using MysignupView.as_view() in the urls.py.

Related

Django - How can this UpdateView return to a filtered TableView?

I have a Django project in which I have a TableView with filters on it. It can redirect to UpdateViews and DeleteViews from the rows in the table, and it works fine, and the UpdateView correctly redirects to the TableView on success.
My issue is, I can't manage to make the UpdateView redirected to the TableView while keeping the filters the TableView had when the UpdateView was called.
The UpdateView has this get_context_data method, in which I'm able to send the filtered URL:
def get_context_data(self, **kwargs):
context = super(SaleUpdateView, self).get_context_data(**kwargs)
...
context['referrer'] = self.request.META.get('HTTP_REFERER')
return context
I made a button in the HTML template to redirect to that referrer, which should redirect to the filtered TableView, but it redirects me to the unfiltered TableView. I think it has to do with my form_valid method and get_success_url method:
def form_valid(self, form):
...
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self, form):
...
return reverse_lazy('sale_list')
How can I access either the self.request.META.get('HTTP_REFERER') or the referer data I sent to the template, in the context of the get_success_url method?
I imagine there must be better ways to solve this, but I solved the issue by doing the following:
1. Sending the referer to the UpdateView's template like this:
def get_context_data(self, **kwargs):
context = super(SaleDeleteView, self).get_context_data(**kwargs)
context['referrer'] = self.request.META.get('HTTP_REFERER')
return context
2. Adding it to the template's <form> in a hidden input like this:
<input name="referrer" id="id_referrer" type="hidden" value="{{ referrer }}">
3. Retrieving it in the get_success_url method in my UpdateView
def get_success_url(self):
referrer = self.request.POST['referrer']
if str(referrer) not in ['', 'None']:
return referrer
return reverse_lazy('sale_list')
I added that last validation in case the user reloads the UpdateView, in which case the referer would be empty.

GenericViews - and pushing model name in URL

using Django Generic CreateView - is it possible for me to pass a value into the CreateView from the URL call, that defines which model/table to base the view on?
I did try get_context_data but believe that is not the solution, as I think it only pushes it to the rendered template.
You will see from my scripts - I am pushing the value 'syslog_policy' - i would like the view to set the model variable to be, what-ever value I push from the URL.
The reason for this, I have some pages/models that are similar - so rather than create multiple html pages and views - I wouldn't need to if I could get this to work.
URL Call
<li>Update/Delete Policies</li>
urls.py
path('HardenTemplateCreate/<str:element>', HardenTemplateCreate.as_view(success_url="/security_tooling/add_success") ,name="HardenTemplateCreate")
views.py
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['element']= self.kwargs['element']
print(context['element'])
return context
model = !!<NEED VALUE SUPPLIED IN URL HERE>!!
fields = ['name','template']
template_name = 'security_app/add.html'```
This would assume that all the models we are working with here belong to the same app (main) - if not, you also need to pass that to form kwargs and handle accordingly. In forms.py:
from django.apps import apps
from django.forms.models import fields_for_model
class VariableModelForm(forms.Form):
def __init__(self, *args, **kwargs):
model_name = kwargs.pop('model_name', None)
model = apps.get_model(app_label='main', model_name=model_name)
model_fields = fields_for_model(model)
super(VariableForm, self).__init__(*args, **kwargs)
for field in model_fields:
self.fields[field] = model_fields[field]
In your CreateView:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form']= VariableModelForm(model_name=self.kwargs['modelname'])
return context
You grab the model name from the url kwargs, pass it to your form as an extra positional argument, and use it in your form's init method to set up the fields.

Subclass a view in django-registration-redux

I'm using Django-registration-redux and I want give more data to a view to render my base template. I read the example in doc.
My url.py:
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# context['book_list'] = Book.objects.all() # example in doc
context_dict = services.get_base_data_for_views(request)
return context_dict
urlpatterns = [
...
path('accounts/password/change/', MyPasswordChangeView.as_view(
success_url=reverse_lazy('auth_password_change_done')), name='auth_password_change'),
...
]
I have the extra data in services.py but this code gives error:
name 'request' is not defined
So context_dict isn't defined. Where can I take my request from? Mainly I need the user (but print(user)= 'user' is not defined). Or should I write another function?
In methods of Django class based views, you can access the request with self.request.
class MyPasswordChangeView(PasswordChangeView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context_dict = services.get_base_data_for_views(self.request)
return context_dict
Therefore you can access the user with self.request.user. Normally you would want to use login_required or LoginRequiredMixin so that only logged-in users can access the view, but in your case PasswordChangeView takes care of that for you.

How can I handle Django login and signup on the same page with class based views?

I want to create one page with both a login and signup form. Per this answer: https://stackoverflow.com/a/1395866/2532070, the best way is to use a separate <form action="{{url}}" tag for each form, and use two different views to handle the POST data for each form. My problem is that using the same view would allow me to pass the errors back to the forms, but if I use separate views with separate urls, I have to redirect the user back to the original page and add these parameters as part of a query string, which doesn't seem very efficient.
My Urls:
url(r'^$', HomePageView.as_view(), name="home_page"),
url(r'^profile/(?P<pk>\d+)/$', MemberUpdate.as_view(template_name="profile.html"), name="profile_page"),
url(r'^signup/$', SignupUser.as_view(), name="signup_user"),
My views:
class HomePageView(TemplateView):
template_name = "index.html"
login_form = AuthenticationForm()
signup_form = UserCreationForm()
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context['login_form'] = self.login_form
context['signup_form'] = self.signup_form
context['signup_action'] = reverse("signup_user")
return context
class SignupUser(CreateView):
model = settings.AUTH_USER_MODEL
form_class = MemberForm
template_name = "index.html"
def get_success_url(self):
return reverse("profile_page", args=[self.object.pk])
def form_invalid(self, form):
# here, how do I pass form.errors back to the home_page?
# I know messages framework is possible but this isn't as
# easy to add each error to its respective field as
# form.errors would be.
return HttpResponseRedirect(reverse('home_page'))
...and I would have a third view for the login form's POST data. Is this an acceptable way to manage my forms/views, or am I better off simply writing one overall view that distinguishes between the signup and login form within its post method with an if statment?

Access named URL parameter in Template or Middleware

In my url conf, I have several URL's which have the same named parameter, user_id.
Is it possible to access this parameter either in a middleware - so I can generically pass it on to the context_data - or in the template itself?
Sample URL conf to illustrate the question:
url(r'^b/(?P<user_id>[0-9]+)/edit?$', user.edit.EditUser.as_view(), name='user_edit'),
url(r'^b/(?P<user_id>[0-9]+)/delete?$', user.delete.DeleteUser.as_view(), name='user_delete')
For class based views, the view is already available in the context, so you dont need to do anything on the view side. In the template, just do the following:
{{ view.kwargs.user_id }}
See this answer
If you need this data in the template, just override your view's get_context_data method:
class MyView(View):
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['user_id'] = self.kwargs.get('user_id')
return context
For function based views:
template
{% url 'view' PARAM=request.resolver_match.kwargs.PARAM %}
views.py
def myview(request, PARAM):
...
Django 2.2