Inspect response when i use a view Class-based views - Django - python

I need to inspect the response for know the params of pagination. I try used Pdb but the application stops. I think to overwrite some method like def dispatch(self, request, *args, **kwargs): but i don't know if the best way, someone could guide me ?
class PostsFeedView(LoginRequiredMixin, ListView):
template_name = 'posts.html'
model = Post
ordering = ('-created',)
paginate_by = 10
context_object_name = 'posts'
# import pdb; pdb.set_trace()

You can override get:
class PostsFeedView(LoginRequiredMixin, ListView):
...
def get(self, *args, **kwargs):
response = super().get(*args, **kwargs)
import pdb; pdb.set_trace()
return response

Related

django-filter according to the logged user

I am using the django_filters to filtering the information. However, it is showing the data of all regitered user of my system. I need show only the data of logged user.
Follow the files:
filters.py
import django_filters
from apps.requisitos.models import Requisito
class RequisitoFilter(django_filters.FilterSet):
class Meta:
model = Requisito
fields = ['nomeRequisito', 'projeto']
views.py
class RequisitoList(ListView):
paginate_by = 10
model = Requisito
def get_queryset(self):
usuarioLogado = self.request.user
return Requisito.objects.filter(user=usuarioLogado)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = RequisitoFilter(self.request.GET, queryset=self.queryset)
return context
the loop for of html page
{% for requisito in filter.qs %}
thank you very much
You need to pass the result of get_queryset to the queryset parameter:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = RequisitoFilter(
self.request.GET,
queryset=self.get_queryset()
)
return context
Note: You might want to consider using a FilterView [GitHub],
this view implements most of the ListView [Django-doc],
and encapsulates logic to use a filter_class.

How do I pass a variable in the URL to a Django list view?

First things first, I want to state I have seen the post created here. The problem is that I am still very new to the Django framework and every attempt I had at implementing this strategy into my code failed. Anyways, I was curious about how I could pass a string value from the URL into my listview. In my case, the variable named item so I can do a filtered query. This was extremely easy to do on function-based views, but I am struggling to do the same on these class-based views. Thanks!
Class Based View:
class PostListView(ListView):
model = Post.objects.get(subject_name=item)
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 5
Routing:
path('<str:item>/', PostListView.as_view(), name='post-view')
You can add get method to your PostListView:
def get(self, request, *args, **kwargs):
item = kwargs[“item”]
// use the item variable here
return super().get(request, *args, **kwargs)
Same thing if you need to correct your context:
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['item'] = kwargs['item']
return data

Use variable with TemplateView

I used to have my pages in Django defined with functions like this:
def pdf(request):
return render(request, 'blog/pdf.html', {'title': 'PDF files'})
Where I was using a Title var for html page title. I started to use a TemplateView class for my pages and I'm not sure how to use the same title inside of something like this:
class About(LoginRequiredMixin, TemplateView):
template_name = 'blog/about.html'
Try this,
class About(LoginRequiredMixin, TemplateView):
template_name = 'blog/about.html'
def get_context_data(self, *args, **kwargs):
context = super(About, self).get_context_data(*args, **kwargs)
context['title'] = 'PDF files'
return context

How to populate formview with model data when fetched via GET

I have the form display info via GET request, currently I assign a new form in get_context_data, is there a better way to do it? And http decorator doesn't work too.
#require_http_methods(['GET',])
class UniversityDetail(SingleObjectMixin, FormView):
model = KBUniversity
form_class = KBUniversityForm
template_name = 'universities/form.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(UniversityDetail, self).get(self, request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(UniversityDetail, self).get_context_data(**kwargs)
context['form'] = KBUniversityForm(instance=self.object)
context['university_id'] = self.object.pk
return context
Use UpdateView instead of FormView with SingleObjectMixin. In 99% of the cases you should not override the get method.

'User' object has no attribute 'get'

I am trying to construct a ModelForm from this solution here, however i am getting this error:
'User' object has no attribute 'get'
The idea is to get ModelForm to construct a form that when submitted the user logged in updates the entry.
The models.py is:
class UserDetailsForm(ModelForm):
class Meta:
model = UserProfile
fields = ['mobile_phone']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(UserDetailsForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(UserDetailsForm, self)
if self.request:
obj.user = UserProfile.objects.get(user=self.request.user)
obj.save()
And my model in models.py is
class UserProfile(models.Model):
user = models.OneToOneField(User)
mobile_phone = models.CharField(max_length=30,help_text='Max 30 characters.',blank=True)
#have shortened this for simplicity
def __unicode__(self):
return self.mobile_phone
At the request here is a traceback of the issue from views.py:
userprofile = UserProfile.objects.get(user=request.user)
if request.method == 'POST':
form = UserDetailsForm(request.user, request.POST, request.FILES)
if form.is_valid(): # it dies here
form.save()
return HttpResponseRedirect('/members-contact/')
Writing this answer because I was bitten twice in a single week by this error.
Came to this question and it was no use in helping me figure out the problem.
The problem with this code is that you have passed request.user an object into the init function of the UserDetailsForm. And your definition for init does not handle what happens with request.user.
userprofile = UserProfile.objects.get(user=request.user)
if request.method == 'POST':
====>form = UserDetailsForm(request.user, request.POST, request.FILES)
if form.is_valid(): # it dies here
form.save()
return HttpResponseRedirect('/members-contact/')
See arrow. If you compare that with your definition for the __init__of user details form. You can see init is not expecting that request.user
class UserDetailsForm(ModelForm):
class Meta:
model = UserProfile
fields = ['mobile_phone']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(UserDetailsForm, self).__init__(*args, **kwargs)
Note there are legitimate reasons why one would write the init to pass in an object.
def __init__(self, some_object, *args, **kwargs):
super(SomeFormClass, self).__init__(self, *args, **kwargs)
self.fields['some_field'].queryset = SomeModel.objects.filter(some_field = some_object)
Also Note that default def of __init__ for modelform has __init__(self, *args, **kwargs)
The dynamic form initialisation here above is a good example.
It appears that django is treating the passed in variable in this case request.user as some_field and is trying to call a method called get which the 'UserModel' does not have. If you check the stack trace you will notice. The below stack trace is an example simulated.
Traceback (most recent call last):
File "/home/user/.local/lib/python3.5/site-packages/django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
return render(request, self.template_name, context)
File "/home/user/.local/lib/python3.5/site- packages/django/shortcuts.py", line 30, in render
content = loader.render_to_string(template_name, context, request, using=using)
---
---
---
packages/django/forms/forms.py", line 297, in non_field_errors
return self.errors.get(NON_FIELD_ERRORS, self.error_class(error_class='nonfield'))
File "/home/user/.local/lib/python3.5/site-packages/django/forms/forms.py", line 161, in errors
self.full_clean()
---
---
---
self._clean_fields()
File "/home/user/.local/lib/python3.5/site-packages/django/forms/forms.py", line 382, in _clean_fields
===>value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))<====
File "/home/sodara/.local/lib/python3.5/site-packages/django/forms/widgets.py", line 238, in value_from_datadict
====> return data.get(name) <====
AttributeError: 'SomeObject' object has no attribute 'get'
data.get is the return value the result of the method call field.widget.value_from_data_dict ...
if you notice, the SomeObject is being treated as the data here whoes get method is being called.
To answer the question, either define init to handle the request.user
def __init__(self, user, *args, **kwargs):
super(YourFormClass, self).__init__(*args, **kwargs):
self.fields["some_field"].some_attr = user
Or call the form without the request.user
`form = YourFormClass(request.POST, request.FILES)`
If you decide to go with option one. You have to remember to call super before calling self.fields. Because self.fields is created by the super method. If you dont you will run into another attributeerror no field named fields.
Edit
Django provides a convenient method get_form_kwargs for adding attributes to the init of form views that inherit from django.views.generic.edit.ModelFormMixin such as FormView.
class MyFormView(FormView):
form_class = MyModelFormClass
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class MyModelFormClass(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user') # Important to do this
# If you dont, calling super will fail because the init does
# not expect, user among the fields.
super().__init__(*args, **kwargs)
self.fields['some_field'].queryset = SomeModel.objects.filter(user=user)
You need something a bit simpler. Have this as your model form:
class UserDetailsForm(ModelForm):
class Meta:
model = UserProfile
fields = ['mobile_phone']
In your view:
from django.core.urlresolvers import reverse_lazy
from django.views.generic import UpdateView
from .models import UserDetailsForm, UserProfile
class UpdateProfile(UpdateView):
template_name = 'users/update_profile.html'
form_class = UserDetailsForm
model = UserProfile
success_url = reverse_lazy('home')
def get_object(self, queryset=None):
'''This loads the profile of the currently logged in user'''
return UserProfile.objects.get(user=self.request.user)
def form_valid(self, form):
'''Here is where you set the user for the new profile'''
instance = form.instance # This is the new object being saved
instance.user = self.request.user
instance.save()
return super(UpdateProfile, self).form_valid(form)
In your urls.py, you need to make sure that the view is called with a logged in user:
from django.contrib.auth.decorators import login_required
from django.views.generic TemplateView
from .views import UpdateProfile
urlpatterns = patterns('',
(r'^profile/update/$', login_required(UpdateProfile.as_view())),
(r'^$', TemplateView.as_view(template='index.html'), name='home'),
)
form = UserDetailsForm(request.user, request.POST, request.FILES)
The problem is that you pass the user object as a positional argument, while your form expects the first positional argument to be the form data. Meanwhile, your form expects a keyword argument request that contains the request object, but you're not passing such an argument. Change the above line to:
form = UserDetailsForm(request.POST, request.FILES, request=request)
I can't see your full view function, but for simple form handling you might want to consider using a class-based view, based on Django's UpdateView, like Burhan suggested.
at __init__
instead of :
return super(UserDetailsForm, self).__init__(*args, **kwargs)
try:
forms.ModelForm.__init__(self, *args, **kwargs)
it works for me..
for visitors using get method here:
from django.contrib.auth.models import User
u = User.objects.all()[0]
print(u.get('username'))
# switch the line above to below
print(getattr(u, 'username'))

Categories