django-endless with class based views example - python

I'm using Class Based Views for the first time. I'm having trouble understating how using class based views I would implement django-endless-pagination twitter styling paging.
Could I have an example of how one would go about this?
This is my view:
class EntryDetail(DetailView):
"""
Render a "detail" view of an object.
By default this is a model instance looked up from `self.queryset`, but the
view will support display of *any* object by overriding `self.get_object()`.
"""
context_object_name = 'entry'
template_name = "blog/entry.html"
slug_field = 'slug'
slug_url_kwarg = 'slug'
def get_object(self, query_set=None):
"""
Returns the object the view is displaying.
By default this requires `self.queryset` and a `pk` or `slug` argument
in the URLconf, but subclasses can override this to return any object.
"""
slug = self.kwargs.get(self.slug_url_kwarg, None)
return get_object_or_404(Entry, slug=slug)

Since this is a broad question, I would like to combine several solutions for pagination now.
1.Use the generic ListView:
from django.views.generic import ListView
class EntryList(ListView):
model = Entry
template_name = 'blog/entry_list.html'
context_object_name = 'entry_list'
paginate_by = 10
It would be way faster using only urls.py:
url(r'^entries/$', ListView.as_view(model=Entry, paginate_by=10))
So basically you don't need django-endless-pagination in this solution. You can check the example of template here: How do I use pagination with Django class based generic ListViews?
2.Use django-endless-pagination's AjaxListView:
from endless_pagination.views import AjaxListView
class EntryList(AjaxListView):
model = Entry
context_object_name = 'entry_list'
page_template = 'entry.html'
Or faster (again) with urls.py only:
from endless_pagination.views import AjaxListView
url(r'^entries/$', AjaxListView.as_view(model=Entry))
Reference: http://django-endless-pagination.readthedocs.org/en/latest/generic_views.html
If anyone knows different solution, please comment.

Related

Class based view won't work while function based view works(Django)

When I try to create a function based view it would work, displaying my queryset. This is the code I used bellow.
in views.py
def restaurant_listview(request):
template_name ="restaurant/restaurantlist.html"
query_set = Restaurant.objects.all() #all the objects that are stored in da DB
context={"list": query_set}
return render(request,template_name, context)
But when I try to do it as a class based view it doesn't show my Queryset.
in views.py
`class RestaurantListView(ListView):
queryset = Restaurant.objects.all()
template_name ="restaurant/restaurantlist.html"`
in urls.py
path('restaurants', RestaurantListView.as_view()
How can i solve this problem?
I think you should change your context configs in your RestaurantListView, like:
class RestaurantListView(ListView):
queryset = Restaurant.objects.all()
template_name ="restaurant/restaurantlist.html"`
context_object_name = 'list'
because it seems you used the old context name in your template codes.

how can I render a view only when a certain field is True? - Django

I have created detailed views for the posts in my Django-based blog using the DetailView generic class and everything works fine so far. The problem, however, is that I have a field in my post model that is used to set the status of the posts (active, inactive, blocked) and I only want to render the detailed views when the status is active. If anyone knows of a way to achieve this, please let me know and I ask that you be as detailed as possible.
views.py
from .models import Post
from django.views.generic import DetailView
class PostDetailView(DetailView):
model = Post
context_object_name = 'post'
template_name = 'blog/post-detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['title'] = Post.objects.filter(slug=self.object.slug).first()
return context
In your DetailView you can filter the queryset, for example you can filter with:
from django.views.generic import DetailView
class PostDetailView(DetailView):
queryset = Post.objects.filter(active=True)
# …
The DetailView will retrieve the element based on the primary key and/or slug on the queryset, so if the element is not in the filtered queryset, then you will retrieve a 404 error.
Here we assume that the Post model has an active field:
class Post(models.Model):
# …
active = models.BooleanField()
# …
Given the field and values are different, you should of course filter the queryset accordingly.

test_func for UserPassesTestMixin with get_object does not work with ListView

in the contacts section of the dashboard of my projects, saved contacts are only visible to the author but previously they are visible to everyone because I forgot to include UserPassesTestMixin in CBV. I included but browser showed me the error named NotImplemented test_func, I also implemented test_func
views.py
class ContactListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
model = ClientContact
template_name = 'site/contacts.html'
context_object_name = 'contacts'
ordering = ['created_at', '-updated_at']
def test_func(self):
contact = self.get_object()
if self.request.user == contact.author:
return True
return False
it says again NotImplemented test_func, as well as get_oject, is an unresolved ref in ListView
I am sure I am doing something wrong but I cannot find my mistake. Please if anyone who knows this, correct me! Thank you
ListView is for displaying multiple objects, so it doesn't make sense to call get_object() (which is for views for a single object like DetailView).
The usual approach for list views is to override get_queryset, and filter the queryset to only show that user's objects.
class ContactListView(LoginRequiredMixin, ListView):
model = ClientContact
template_name = 'site/contacts.html'
context_object_name = 'contacts'
ordering = ['created_at', '-updated_at']
def get_queryset(self):
return super(ContactListView, self).get_queryset().filter(author=self.request.user)
You already have LoginRequiredMixin, which will handle the case when the user is not logged-in.
If you wanted to filter the queryset in multiple list views, you could write a mixin, for example:
class AuthorMixin(object):
def get_queryset(self):
return super(AuthorMixin, self).get_queryset().filter(author=self.request.user)
Then use it in your view as:
class ContactListView(LoginRequiredMixin, AuthorMixin, ListView):
...
Note that the above is untested, it requires LoginRequiredMixin (because it doesn't handle the anonymous user case), and it will only work if the user foreign key is named author. You could improve the mixin, but you might prefer to repeat the get_queryset method.

How can I combine two views and two forms into one single template?

I have two separate class-based views and would like to keep their functionality, and have the two CBVs point to the same template (I'm trying to bring two separate forms into a single page).
More specifically, I am trying to subclass/combine this email view, and this password change view, so that I can have them point to the same template, as I ultimately would like both forms on the same page.
I've attempted to do this by subclassing them into my own views:
class MyEmailUpdateView(LoginRequiredMixin, EmailView):
template_name = 'account/account_settings'
success_url = reverse_lazy('settings')
def form_valid(self, form):
return super(SettingsUpdateView, self).form_valid(form)
class MyPasswordUpdateView(LoginRequiredMixin, PasswordChangeView):
template_name = 'account/account_settings'
success_url = reverse_lazy('settings')
def form_valid(self, form):
return super(SettingsUpdateView, self).form_valid(form)
But I am now finding out due to errors, one by one, that it appears nothing from the parent class is actually transferred over to my custom class unless I manually bring it in(success_url, methods, etc). Even then, the code from the original classes that I am subclassing is pointing elsewhere.
SO, when combining these two views, do I need to copy all of the original code into my custom subclass views?
Is this the proper way to accomplish it? How can I combine these two views? I'm ultimately looking for a way to have both of their forms on a single page in my own app. Is there possibly a simpler way to accomplish this using the library's provided templates?
You can use Django Multi Form View to combine many forms in view
After install you can use it like below:
class MultiFView(MultiFormView):
form_classes = {
'email_form' : AddEmailForm,
'change_password_form' : ChangePasswordForm
}
record_id = None
template_name = 'web/multi.html'
def forms_valid(self, forms):
email = forms['email_form'].save(commit=False)
email.save()
return super(MultiFView, self).forms_valid(forms)
and in template:
{{ forms.email_form.as_p }}
{{ forms.change_password_form.as_p }}
I think You can use the default class in django to a achieve the same result.
As far as i understood i got the scenario like this we have two django forms and we need it to be used in same template if that is the scenario we can use the LoginView from django.contrib.auth.views which has several customizable option like you can give the additional form like this
class LoginUserView(LoginView):
authentication_form = LoginForm
extra_context = {"register_form": RegistrationForm}
template_name = 'accounts/index.html'
it will be using the get context data method to update the form which you will be able to get in the template and use accordingly .If you are not wishing to use the code like this you can still use it like this
class MyEmailUpdateView(LoginRequiredMixin, EmailView):
form_class = EmailForm
template_name = 'account/account_settings'
success_url = reverse_lazy('settings')
def get_context_data(self, **kwargs):
context = super(MyEmailUpdateView, self).get_context_data(**kwargs)
context['password_reset_form'] = ResetPasswordForm
return context
def form_valid(self, form):
return super(MyEmailUpdateView, self).form_valid(form)
Then you can handle your post in the form valid accordingly as your requirement.
Hope that helps get back if you need any additional requirement.
This can be solved by implementing a (kind of) partial update method for your view.
Tools:
First protect your sensitive data:
sensitive_variables decorator:
If a function (either a view or any regular callback) in your code uses local variables susceptible to contain sensitive information, you may prevent the values of those variables from being included in error reports using the sensitive_variables decorator
sensitive_post_parameters() decorator:
If one of your views receives an HttpRequest object with POST parameters susceptible to contain sensitive information, you may prevent the values of those parameters from being included in the error reports using the sensitive_post_parameters decorator
Create some code after:
Use ModelForm to create a form with specific fields of interest for your view. Don't include the password field, because we will add it in a different way to suit our needs:
myapp/forms.py:
class PartialUpdateForm(forms.ModelForm):
new_password = forms.CharField(
required=False, widget=forms.widgets.PasswordInput
)
class Meta:
model = MyUser
fields = ('email', 'other_fields',...)
Here you can use exclude instead of fields if you want to keep every other field except the password: ex. exclude = ('password',)
Use an UpdateView to handle the hustle and override it's form_valid method to handle the partial update:
myapp/views.py:
class MyUpdateView(UpdateView):
template_name = 'account/account_settings'
form_class = PartialUpdateForm
success_url = reverse_lazy('settings')
#sensitive_variables('new_password')
#sensitive_post_parameters('new_password')
def form_valid(self, form):
clean = form.cleaned_data
new_password = clean.get('new_password')
if new_password:
form.instance.password = hash_password(new_password)
return super().form_valid(form)
Finally, create a url for that view:
myapp/urls.py:
...
url(r'^your/pattern/$', MyUpdateView.as_view()),
This way you can handle:
Email AND password update at the same time
Only email update.
Only password update.
Using code from this solution: Django: Only update fields that have been changed in UpdateView

Pass variable to TemplateView [duplicate]

I have a custom class-based view
# myapp/views.py
from django.views.generic import *
class MyView(DetailView):
template_name = 'detail.html'
model = MyModel
def get_object(self, queryset=None):
return queryset.get(slug=self.slug)
I want to pass in the slug parameter (or other parameters to the view) like this
MyView.as_view(slug='hello_world')
Do I need to override any methods to be able to do this?
If your urlconf looks something like this:
url(r'^(?P<slug>[a-zA-Z0-9-]+)/$', MyView.as_view(), name = 'my_named_view')
then the slug will be available inside your view functions (such as 'get_queryset') like this:
self.kwargs['slug']
Every parameter that's passed to the as_view method is an instance variable of the View class. That means to add slug as a parameter you have to create it as an instance variable in your sub-class:
# myapp/views.py
from django.views.generic import DetailView
class MyView(DetailView):
template_name = 'detail.html'
model = MyModel
# additional parameters
slug = None
def get_object(self, queryset=None):
return queryset.get(slug=self.slug)
That should make MyView.as_view(slug='hello_world') work.
If you're passing the variables through keywords, use what Mr Erikkson suggested: https://stackoverflow.com/a/11494666/9903
It's worth noting you don't need to override get_object() in order to look up an object based on a slug passed as a keyword arg - you can use the attributes of a SingleObjectMixin https://docs.djangoproject.com/en/1.5/ref/class-based-views/mixins-single-object/#singleobjectmixin
# views.py
class MyView(DetailView):
model = MyModel
slug_field = 'slug_field_name'
slug_url_kwarg = 'model_slug'
context_object_name = 'my_model'
# urls.py
url(r'^(?P<model_slug>[\w-]+)/$', MyView.as_view(), name = 'my_named_view')
# mymodel_detail.html
{{ my_model.slug_field_name }}
(both slug_field and slug_url_kwarg default to 'slug')
If you want to add an object to the context for the template you can override get_context_data and add to its context. The request is also a part of self in case you need the request.user.
def get_context_data(self, **kwargs):
context = super(MyTemplateView, self).get_context_data(**kwargs)
if 'slug' in self.kwargs:
context['object'] = get_object_or_404(MyObject, slug=self.kwargs['slug'])
context['objects'] = get_objects_by_user(self.request.user)
return context
You can pass parameters from urls.py
https://docs.djangoproject.com/en/1.7/topics/http/urls/#passing-extra-options-to-view-functions
This also works for generic views. Example:
url(r'^$', views.SectionView.as_view(), { 'pk': 'homepage', 'another_param':'?'}, name='main_page'),
In this case the parameters passed to the view should not necessarily be instance variables of the View class. Using this method you don't need to hardcode default page name into YourView model, but you can just pass it as a parameter from urlconf.
As stated by Yaroslav Nikitenko, if you don't want to hardcode a new instance variable to the View class, you can pass extra options to view functions from urls.py like this:
url(r'^$', YourView.as_view(), {'slug': 'hello_world'}, name='page_name')
I just wanted to add how to use it from the view. You can implement one of the following methods:
# If slug is optional
def the_function(self, request, slug=None):
# use slug here
# if slug is an optional param among others
def the_function(self, request, **kwargs):
slug = kwargs.get("slug", None)
other_param = kwargs.get("other_param", None)
# If slug is required
def the_function(self, request, slug):
# use slug here
For django 3.0, this is what worked for me:
# myapp/views.py
from django.views.generic import DetailView
class MyView(DetailView):
template_name = 'detail.html'
slug = None
def get_object(self, queryset=None):
self.slug = self.kwargs.get('slug', None)
return queryset.get(slug=self.slug)
# myapp/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('slug/<slug:slug>/', views.MyView.as_view(), name='myview_by_tag'),
]

Categories

Resources