Captured URL parameters in form - django

I am using Userena and I am trying to capture URL parameters and get them to my form but I'm lost how to do this.
What I would like to do in my template is:
Free Plan<br/>
Pro Plan<br/>
Enterprise Plan<br/>
And then in my urls.py
url(r'^accounts/signup/(?P<planslug>.*)/$','userena.views.signup',{'signup_form':SignupFormExtra}),
Then, ideally, I'd like to use that planslug in my forms.py to set the user plan in the profile.
I'm lost how to get the captured URL parameter into the custom form. Can I use the extra_context, do I have to override the Userena signup view?

If you use class based views, you can overwrite the def get_form_kwargs() method of the FormMixin class. Here you can pass any parameters you need to your form class.
in urls.py:
url(r'^create/something/(?P<foo>.*)/$', MyCreateView.as_view(), name='my_create_view'),
in views.py:
class MyCreateView(CreateView):
form_class = MyForm
model = MyModel
def get_form_kwargs(self):
kwargs = super( MyCreateView, self).get_form_kwargs()
# update the kwargs for the form init method with yours
kwargs.update(self.kwargs) # self.kwargs contains all url conf params
return kwargs
in forms.py:
class MyForm(forms.ModelForm):
def __init__(self, foo=None, *args, **kwargs)
# we explicit define the foo keyword argument, cause otherwise kwargs will
# contain it and passes it on to the super class, who fails cause it's not
# aware of a foo keyword argument.
super(MyForm, self).__init__(*args, **kwargs)
print foo # prints the value of the foo url conf param
hope this helps :-)

You can access the url in your template using -
{% request.get_full_path %}
(see the docs for more info).
However if you just want to get the planslug variable then pass it from the view to the template and access it in the template (it's available in the view because it's a named parameter in the url) -
def signup(request, planslug=None):
#
render(request, 'your_template.html', {'planslug':planslug}
and then in your template you get it with -
{% planslug %}
If you're using class based views then you'll need to override get_context_data to add the planslug variable to your context before you pass it to the template-
def get_context_data(self, *args, **kwargs):
context = super(get_context_data, self).get_context_data(*args, **kwargs)
context['planslug'] = self.kwargs['planslug']
return context

Related

ListView with an extra argument

I want to add a parameter somevar to my listview:
{% url 'products' somevar %}?"
in the urls:
path("products/<int:somevar>", ProductListView.as_view(), name = 'products'),
in the views:
class ProductListView(ListView):
def get_template_names(self):
print(self.kwargs) # {"somevar": xxxxx}
return f"{TEMPLATE_ROOT}/products.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.get_products().order_by("number")
print(kwargs) # kwargs is {} here
return context
def get_queryset(self):
return super().get_queryset().order_by("number")
How can I pass the variable to the get_context_data method? I tried defining a get method and call self.get_context_data(**kwargs) within, but this leads to an object has no attribute 'object_list' error.
The View class has different kwargs than the get_context_data method
The kwargs of a View contain the URL Parameters
The kwargs passed to the get_context_data method are passed to the template for rendering
Since you want to access a URL Parameter in get_context_data you would use self.kwargs (self is referring to your View class)

Can I make a Django mixin that adds context variables just before template render?

I have a Django application that uses a JSON API as its data source.
Here's a simplified example of use in one of my views.py:
class GroupsList(LoginRequiredMixin):
def get(self, request, **kwargs):
# Get file list and totals
try:
group_list = group_adapter.list() # makes an API call and ALSO populates a meta info class
except APIAccessForbidden:
return HttpResponseRedirect(reverse('logout'))
return render(request, 'groups/index.html', {
# can I make a mixin to add data here gained from the API call?
'group_list': group_list,
})
This line:
The group_adapter.list() call populates some meta information into another class, that's not related to the group_list itself. I'd like to pass that data to the template. Ordinarily I'd use a context_processor, but when the context processor is called, the API call hasn't been made yet. I could manually check the information and add it to the render() method, but then I'd need to do that in dozens of different views.
Potential Solution #1: Create a Mixin For It
Can I use a mixin here that adds this information to context AFTER the view code runs but BEFORE render passes information to the template?
In other words is there a way to do this:
class GroupsList(LoginRequiredMixin, AddMetaInfoToContextMixin):
and then create a mixin something like this?
class AddMetaInfoToContextMixin(ContextMixin):
def get_context_data(self, **kwargs):
# self.request
context = super().get_context_data(**kwargs)
context['global_meta_information'] = get_global_meta_information()
return context
Potential Solution #2: Make an overridden templateview
Commenter Melvyn pointed out that I can potentially subclass TemplateView and override get_context_data(), so would something like this work?
class TemplateViewWithMeta(TemplateView):
def get_context_data(self, *args, **kwargs):
context = super(Home. self).get_context_data(*args, **kwargs)
context['global_meta_information'] = get_global_meta_information()
return context
class GroupsList(LoginRequiredMixin, TemplateViewWithMeta):
[...]
The typical workflow for a Django generic TemplateView is:
get()
get_context_data()
render_to_response()
So in your case keeping with the spirit of generic views, you could do it like this:
from django.views import generic
class BaseRemoteApiView(generic.TemplateView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.group_list = None
def get(self, request, *args, **kwargs):
try:
self.group_list = group_adapter.list() # makes an API call and ALSO populates a meta info class
except APIAccessForbidden:
return HttpResponseRedirect(reverse('logout'))
return super().get(request, *args, **kwargs)
class RemoteApiContextMixin(generic.base.ContextMixin):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["group_list"] = self.group_list
context["meta_information"] = get_global_meta_information()
return context
class ConcreteRemoteApiView(RemoteApiContextMixin, BaseRemoteApiView):
pass
Of course, you don't have to make 3 classes and can just combine the 3 into one - depends on how mixable you want to be.

Django: ModelChoiceField as MultipleHiddenInput

I am trying to render a ModelChoiceFiel using the MultipleHiddenInput widget but the template does not generate any inputs at all.
Here is what I am trying:
class PresetSelectForm(forms.Form):
presets = forms.ModelChoiceField(queryset=Preset.objects.none(), widget=forms.MultipleHiddenInput())
def __init__(self, presets, *args, **kwargs):
super(PresetSelectForm, self).__init__(*args, **kwargs)
self.fields['presets'].queryset = presets
And in the template I am using the following:
{% csrf_token %}
{{ form }}
The csrf token input is generated, but nothing is for {{ form }}.
What am I missing?
Edit: I am including the essential and relevant code I am using in my view. It's just a FormView, so the form object is automatically created.
class PresetSelectView(FormView):
form_class = PresetSelectForm
The overriden methods are: get_form_kwargs, get_context_data, form_valid, form_invalid and dispatch.
I guess it's worth mentioning that I am not using the form instance anywhere in these methods except in form_valid, where I am getting form.cleaned_data['presets'] but not modifying form at all.
Here is the overriden get_context_data method:
def get_context_data(self, **kwargs):
request = self.request
context = super(PresetSelectView, self).get_context_data(**kwargs)
# now some lines retrieving models
# then we attach some additional attributes to the instances of some of these models (these attributes will be used in the template)
context.update({...})
return context

How To Access Model Class Variable in Django Admin Change Form Template Before Save

Say I have a model in which I have a class variable called documentation. I want to access the documentation class variable in the given models change form template. How can I do this? After the instance has been saved I can access the class variable in the template with {{original.documentation}}.
Example Model
class Person(models.Model):
# How do I access this variable in my change form template
# before saving the new instace?
documentation = "The Person model will be used for all staff including researchers, professors, and authors."
first_name = models.CharField(max_length=255)
This can be done by updating Django view methods in the ModelAdmin class https://docs.djangoproject.com/en/dev/ref/contrib/admin/#other-methods.
def add_extra_context(model, kwargs):
kwargs.setdefault("extra_context", {})
kwargs["extra_context"]["documentation"] = model.__dict__.get('documentation','')
class DocumentableAdmin(admin.ModelAdmin):
def add_view(self, *args, **kwargs):
add_extra_context(self.model, kwargs)
return super(DocumentableAdmin, self).add_view(*args, **kwargs)
def changelist_view(self, *args, **kwargs):
add_extra_context(self.model, kwargs)
return super(DocumentableAdmin, self).changelist_view(*args, **kwargs)
def change_view(self, *args, **kwargs):
add_extra_context(self.model, kwargs)
return super(DocumentableAdmin, self).change_view(*args, **kwargs)
admin.site.register(Person, DocumentableAdmin)
Now the documentation class variable defined in the model will be available in the change form admin template accessible using {{ documentation|safe }}
You can use ModelForms for this. Create a form and refer that in your view like formname = forms.formname(). They you can display whole form using {formname} tag.
Its better to manipulate your variables in forms.py instead for templates. But you can access your variable in template if you want by defining a get_context_data(self, **kwargs) function in your view class like:
def get_context_data(self, **kwargs):
context = super(view_name, self).get_context_data(**kwargs)
context['model_field_list'] = Modelname.objects.get(pk=self.kwargs["modelname_pk"])
return context
And now you can access your variables using {model_field_list.fieldname} tags in templates. Check the documentation on get_context_data function here: documentation

How do I get django url parameters from a view mixin?

Exactly what the title says. I have a mixin that needs to pull in the id of a model field in order to be useful. I assume the easy way to do that would be to pull it from the URL.
class StatsMixin(ContextMixin):
def get_stats_list(self, **kwargs):
# the ??? is the problem.
return Stats.objects.filter(id=???).select_related('url')
def get_context_data(self, **kwargs):
kwargs['stats'] = self.get_stats_list()[0]
print kwargs
return super(StatsMixin, self).get_context_data(**kwargs)
Here's the view implementation for reference.
class ResourceDetail(generic.DetailView, StatsMixin):
model = Submissions
template_name = 'url_list.html'
queryset = Rating.objects.all()
queryset = queryset.select_related('url')
You can access URL parameters in Django by using, self.args and self.kwargs.