Get parameters slugs from the URL - python

I'm trying to get two parameters out of the URL to add to my context.
This is the URL:
url(r'^company/(?P<company>[\w\-\_]+)/?/(?P<program>[\w\-\_]+)/?$', RegistrationView.as_view(),
name='test'),
The view:
class RegistrationView(RegistrationMixin, BaseCreateView):
form_class = AppUserIntroducerCreateForm
template_name = "registration/register_introducer.html"
slug_field = 'company'
def get_context_data(self, *args, **kwargs):
context = super(RegistrationIntroducerView, self).get_context_data(**kwargs)
print(self.get_slug_field())
context['company'] = ??????
context['program'] = ??????
return context
I have tried everything to get the values self.company, kwargs['company'] etc, what I'm I doing wrong here?

Here is SO reference for you .
context = super(RegistrationView, self).get_context_data(**kwargs)
print(self.get_slug_field())
context['company'] = self.kwargs['company']
context['program'] = self.kwargs['program']

Try this
self.kwargs['company']
self.kwargs['program']

The as_view class method of the base class (View) is a closure around a pretty simple view function that accepts the arguments defined in urls.py. It then assigns them as a dictionary to self.kwargs attribute of the view class. Therefore what you need to do in order to access this data is:
self.kwargs['company']
Also, if you inherited your RegistrationView from CreateView instead of BaseCreateView, you'd get SingleObjectTemplateResponseMixin mixed in with your view and the slug_field (along with model or queryset) would be used by get_object method to fetch the desired company. Furthermore, the context variable company containing the Company instance would be already set for you and you would not have to set it yourself.

Related

Is there any way to pass an ID from URL to views.py using generic views?

I need to pass id from the url slug. I am using generic views. This is my code for urls.py:
path('category/<int:pk>/details/',
CategoryDetailView.as_view(),
name='category-details'),
and I need to pass the <int:pk> value into views.py, so I can filter my queryset with this id.
My views.py code:
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, *, object_list=Expense.objects.get_queryset(), **kwargs):
queryset = object_list
return super().get_context_data(
summary_per_year_month = summary_per_year_month(queryset.filter(category_id= <int:pk> ))
)
You can access values from the URL in self.kwargs.
queryset.filter(category_id=self.kwargs['pk'])
Note that your get_context_data is the other way round than normal. Typically, you call super() and then add to the context dict. It looks like your way will work, but it will seem odd to other Django users. You could try writing it as follows:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset=Expense.objects.get_queryset()
context['summary_per_year_month'] = summary_per_year_month(queryset.filter(category_id=self.kwargs['pk']))
return context
Yes, the path parameters are stored in self.kwargs, a dictionary that maps the name of the parameter to the value. So you can make use of:
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, *args, **kwargs):
summary=summary_per_year_month(
Expense.objects.filter(category_id=self.kwargs['pk'])
)
return super().get_queryset(*args, **kwargs, summary_per_year_month=summary)
You use self.kwargs.get('pk').
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, *, object_list=Expense.objects.get_queryset(), **kwargs):
queryset = object_list
return super().get_context_data(
summary_per_year_month = summary_per_year_month(queryset.filter(category_id=self.kwargs.get('pk')))
)
Something that really helped me learn Django was to add breakpoints (pdb) in my code, then run dir() on each object I came across.
For example, dir(self) will tell you what properties and methods 'self' has (ie, kwargs, model, request, etc). Then you can start experimenting around with these properties: self.kwargs, self.request, self.model, etc, see what they return.
Soon enough, you would find out that self.kwargs returns a dictionary of arguments that includes 'pk', which you can access using get(). That's how you can access 'pk'.
To me, this simple trick unlocked most of my understanding of Django and python.

Django: Call custom function within generic views

I'm new to Django and am using Django's generic editing views to add/edit/delete entities. Eg, the views for adding and editing look like this:
class QuoteCreate(CreateView):
template_name = 'quotes/quote_form.html'
model = Quote
fields = ['quote_text']
class QuoteUpdate(UpdateView):
model = Quote
fields = ['quote_text']
This works fine and I'm happy with how everything is rendered. I'd just like to call an extra, custom function whenever a new object is created or edited (to send myself notifications). How can I do that? I couldn't find anything useful in the documentation.
You can call a view within another, which in your example could look like:
views.py
class QuoteCreate(CreateView):
template_name = 'quotes/quote_form.html'
model = Quote
fields = ['quote_text']
object_change = notify_function(foo)
class QuoteUpdate(UpdateView):
model = Quote
fields = ['quote_text']
return = fields
object_change = notify_function(foo)
def notify_function(foo):
# whatever logic is desired to be notified
return [..]
You should rewrite generic view post method putting your function in it.
class QuoteUpdate(UpdateView):
model = Quote
fields = ['quote_text']
def my_custom_function(self):
# your code
def post(self, request, *args, **kwargs):
self.object = self.get_object()
self.my_custom_function()
return super().post(request, *args, **kwargs)

Django: Can't use session vars in ModelForm

I have this session var:
empresa=request.session['codEmp']
I have a ModelForm with a ModelChoiceField:
class AuxiForm(forms.ModelForm):
tipAux = forms.ModelChoiceField(queryset=TipoAux.objects.all(), empty_label=None,
required=True, to_field_name='codigo')
If you see the queryset for tipAux it's currently calling for all the TipoAux objects, but I really need to do a filter, calling only the TipoAux objects that have the same empresa attribute that the user has on his codEmp session var.
I tried by doing:
tipAux = forms.ModelChoiceField(queryset=TipoAux.objects.filter(empresa=request.session['codEmp']),
empty_label=None, required=True,
to_field_name='codigo')
But Django is not allowing me to use request.session in the form.
Any way to handle this?
Try overriding the form's __init__() method and pass the session variable in as an argument to the form:
class AuxiForm(forms.ModelForm):
def __init__(filter_on, *args, **kwargs):
super(AuxiForm, self).__init__(*args, **kwargs)
self.fields['tipAux'] = forms.ModelChoiceField(
queryset=TipoAux.objects.filter(empresa=filter_on),
empty_label=None,
required=True,
to_field_name='codigo'
)
And, in your view.py, you could say something like: form = AuxiForm(data=request.POST, filter_on=request.session['codEmp'])
Alternatively, you could use Django's generic model view. If your form isn't more complicated than the one you posted—you'd just set the queryset attribute. (I'll leave the reading to you because I'm only just getting familiar with generic views myself.)

Class based view that inherits from a custom class based view does not see context variables in parent

I have written a Class based view which acts as a base view for several other class based views. So the other class based views is just subclassing the base view, but the subclassed views are not getting the effect of the get_context_data or form_valid functions, so the context variables set in the base view is not getting sent to the template when requests are executing using the view subclassing the base view, they are only being sent when the base view itself it used.
Class based view:
class PortfolioNewBase(CreateView):
url_name = ''
post_req = False
def form_valid(self, form):
self.post_req = True
return super(PortfolioNewBase, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return super(PortfolioNewBase, self).get_context_data(**kwargs)
def get_success_url(self):
return reverse(self.url_name, args=self.kwargs['profile_id'])
When creating a new class based view which is one of the views that will be using this code it does not get access to the "profile_id" or "post_req" variables for some reason, it does not get sent to the template, but if you only use the base view written above that view will send the variables so that they are available in the view.
Code for one of the class based views using this base view written above:
class PortfolioNewDividend(PortfolioNewBase):
model = Dividend
form_class = DividendForm
template_name = 'plan/portfolio/new/new_dividend.html'
url_name = 'plan:investment-info-dividends-new'
The form works and everything, but the variables in the get_context_data in the parent is apparently not being inherited for some reason which is kind of the point here and the form_valid function is not being run either, the value of the post_req on POST requests done by the PortfolioNewDividend class based view still has the value False.
Why is the PortfolioNewDividend not running the get_context_data and form_valid functions when a request is executed with that view but the functions run if you use the base clase (written above) only ?
One super call too many in there. Change as follows:
def get_context_data(self, **kwargs):
context = super(PortfolioNewBase, self).get_context_data(**kwargs)
context['profile_id'] = self.kwargs['profile_id']
context['post_req'] = self.post_req
return context # You must actually return the modified context!

Updateview with dynamic form_class

I would like to dynamically change the form_class of an UpdateView CBV in Django 1.6.
I've tried to do this using the get_context_data(), but that didn't help since the form is already initialized. So it will need to happen during __init__, I guess.
Here's what I've tried on __init__:
class UpdatePersonView(generic.UpdateView):
model = Person
form_class = ""
def __init__(self, *args, **kwargs):
super(UpdatePersonView, self).__init__(*args, **kwargs)
person = Person.objects.get(id=self.get_object().id)
if not person.somefield:
self.form_class = OneFormClass
elif person.somefield:
self.form_class = SomeOtherFormClass
I'm stuck with a 'UpdatePersonView' object has no attribute 'kwargs' error message when executing person = Person.objects.get(id=self.get_object().id).
When manually specifying the id (e.g. id=9), then the setup works.
How can I get the args/kwargs inside the init method that I'm overriding? Particularly I would need access to the pk.
You should simply override get_form_class.
(Also I'm not sure why you're querying for person: that object is the same is self.get_object() already, so there's no point getting the ID of that then querying again.)
def get_form_class(self):
if self.object.somefield:
return OneFormClass
else:
return SomeOtherFormClass

Categories