Django Model field default from Model - python

Consider two models in my models.py:
Roles:
class Role(models.Model):
role = models.CharField(max_length=255)
nickname = models.CharField(max_length=255)
is_hero = models.BooleanField(default=False)
def __str__(self):
return self.role
and
Players:
class Player(models.Model):
name = models.CharField(max_length=255)
role = models.ForeignKey(Role, on_delete=models.CASCADE)
nickname = models.CharField(max_length=255, default="Use the default nickname from the role you just chose but also be able to change it from within this model.")
is_hero = models.BooleanField(default="Use the default is_hero from the role you just chose but also be able to change it from within this model.")
def __str__(self):
return self.name
Also consider that I already made a role called "Dumbo" with the nickname "Dunm" and is_hero being False.
I now go ahead and try to use the role in my new player after setting my player name, I choose my role but how do I use the values of my now chosen role in my new player as the default for nickname and is_hero and at the same time, allow them to be overridden if feel so?
Thanks,
Edit:
I've overridden all the Django templates. So I'm not making new forms and rendering them in my custom views. I'm really bad with the terminologies, pardon me. I hope this makes sense.
{% load fieldcss %}
<div class="card">
<div class="card-header">
{% if fieldset.name %}<h4 class="card-title">{{ fieldset.name }}</h2>{% endif %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
</div>
<div class="card-body">
{% for line in fieldset %}
<div class="row">
{% for field in line %}
{% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
{% if name == "CheckboxInput" %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{{ field|addlabel:field.field.label|safe }}
{% if field.is_readonly %}
<div class="readonly">{{ field.contents }}</div>
{% else %}
<div class="col-sm-10">
{% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
<div class="form-group">
{{ field|addclass:field.field.auto_id|safe }}
{% if field.field.help_text %}
<span class="form-text">{{ field.field.help_text|safe }}</span>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</fieldset>

This is not something you can do in the model, but by passing the values to the form from the view at creation time. For example:
class PlayerCreateForm(forms.ModelForm):
class Meta:
model = Player
fields = ('name', 'nickname', 'is_hero')
def create_player_from_role(request, role_id):
role = get_object_or_404(Role, role_id)
if request.method == 'POST':
form = PlayerCreateForm(request.POST)
if form.is_valid():
player = form.save(commit=False)
player.role = role
player.save()
return redirect('/')
else:
form = PlayerCreateForm(initial={'nickname': role.nickname, 'is_hero': role.is_hero})
return render(request, 'create_player.html', {'form': form})

Related

How to integrate a function based view into a class based view in Django?

In my site I have 2 sections for users. The user posts page and the profile page. The profile page has all their info on it, so username, description, first/last name, etc. And the user posts page has all their posts on it. However, I want to integrate them together somehow.
Here is some of the code.
Here is the view for the User Posts
class UserPostListView(ListView):
model = Post
template_name = 'mainapp/user_posts.html'
context_object_name = 'posts'
def get_queryset(self):
user = get_object_or_404(User,username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-published_date')
As you can see, I am returning the specific users posts.
And now here is my profile view
def view_profile(request,pk=None):
if pk:
user_profile = User.objects.get(pk=pk)
else:
user_profile = request.user
context = {'user':user_profile}
return render(request,'mainapp/profile.html',context)
It returns all the user's info.
Here is the HTML code for both the profile and user posts page
{% block content %}
<div class="profile-page-container">
<div class="profile-page-info">
<div class="profile-page-banner">
<div class="profile-page-banner-background">
<!-- <img src="https://cdn.pixabay.com/photo/2017/08/30/01/05/milky-way-2695569_960_720.jpg" alt="{{ user }}'s Background Image" > -->
</div>
<div class="profile-page-banner-text">
<h2 title="{{ user }}" id="username-profile-page">{{ user|safe|linebreaksbr|truncatechars_html:25 }} {% if user.userprofileinfo.verified %} <span class="image-profile-verified"><img draggable="false" title="Verified User" class="verifed" src="{% static 'images\verified.png' %}" alt="verified" width="25" height="25" srcset=""></span> {% endif %}</h2>
<p>{{ user.first_name }} {{ user.last_name }}</p><br>
</div>
</div>
<div class="profile-page-user-desc-box">
<p>{{ user.userprofileinfo.description }}</p>
<p>{{ user.userprofileinfo.website }}</p>
<p>{{ user.userprofileinfo.joined_date |date:"F d Y" }}</p>
</div>
<br>
{% if user.userprofileinfo.image %}
<img class="rounded-circle account-img" src="{{ user.userprofileinfo.image.url }}" alt="{{ user }}'s Profile Picture'">
{% endif %}
</div>
<div class="user-post-user-profile-page">
<h1 title="{{ user }}">Posts</h1>
{% for post in posts %}
<div class="content">
<div class="post">
<h1 class='posttitle'>{{ post.title }}</h1>
<img class="user-image" src="{{ post.author.userprofileinfo.image.url }}" alt="pfp" width="20%" height="20%">
{% if post.published_date %}
<!-- <div class="postdate">
<i class="fas fa-calendar-day"></i> <p>Posted {{ post.published_date|timesince }} ago</p>
</div> -->
<div class="posted-by">
<p>Posted by <strong>{{ post.author }}</strong> {{ post.published_date|timesince }} ago</p>
</div>
{% else %}
<a class="pub-post" href="{% url 'mainapp:post_publish' pk=post.pk %}">Publish</a>
{% endif %}
<p class='postcontent' >{{ post.text|safe|linebreaksbr }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
And here is the user_posts page
{% block content %}
<div class="sidebar">
<p class="active" href="#">{{ view.kwargs.username }}</p>
<button class="commentbtn"><a class="aclass" href="#">Connect with {{ view.kwargs.username }}</a></button>
<p>{{ user.userprofileinfo.email }}</p>
<p>Lorem</p>
</div>
{% for post in posts %}
<div class="content">
<div class="post">
<h1 class='posttitle'>{{ post.title }}</h1>
<img class="user-image" src="{{ post.author.userprofileinfo.image.url }}" alt="pfp" width="20%" height="20%">
{% if post.published_date %}
<!-- <div class="postdate">
<i class="fas fa-calendar-day"></i> <p>Posted {{ post.published_date|timesince }} ago</p>
</div> -->
<div class="posted-by">
<p>Posted by <strong>{{ post.author }}</strong> {{ post.published_date|timesince }} ago</p>
</div>
{% else %}
<a class="pub-post" href="{% url 'mainapp:post_publish' pk=post.pk %}">Publish</a>
{% endif %}
<p class='postcontent' >{{ post.text|safe|linebreaksbr }}</p>
</div>
</div>
{% endfor %}
{% endblock %}
I have tried to merge the FBV into the CBV by cutting it and pasting it below the get_queryset method So like this
def get_queryset(self):
#... code here
def view_profile(request,pk=None):
#... code here
However this did not work. I am just curious as to how I can integrate both together so I can have the best of both worlds in one place
EDIT: Here are the models
class UserProfileInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,max_length=30)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
description = models.CharField(max_length=150)
website = models.URLField(max_length=200)
image = ProcessedImageField(upload_to='profile_pics',
processors=[ResizeToFill(150, 150)],
default='default.jpg',
format='JPEG',
options={'quality': 60})
joined_date = models.DateTimeField(blank=True,null=True,default=timezone.now)
verified = models.BooleanField(default=False)
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
and now the post
class Post(models.Model):
author = models.ForeignKey(User,related_name='posts',on_delete=models.CASCADE)
title = models.CharField(max_length=75)
text = models.TextField()
group = models.ForeignKey(Group,null=True,blank=True,related_name='posts',on_delete=models.CASCADE)
created_date = models.DateTimeField(default=timezone.now)
image = models.ImageField(upload_to='post_images',blank=True,null=True)
file = models.FileField(upload_to='post_files',blank=True,null=True)
published_date = models.DateTimeField(blank=True,null=True,auto_now_add=True)
comments_disabled = models.BooleanField(default=False)
NSFW = models.BooleanField(default=False)
spoiler = models.BooleanField(default=False)
tags = TaggableManager()
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
Also in continuation to Ian answer, if you have a direct relationship between models then you can simply get the posts for the particular user like this:
def view_profile(request,pk=None):
if pk:
user_profile = User.objects.get(pk=pk)
user_posts = Posts.objects.filter(user__id=pk) #<---add these
else:
user_profile = request.user
user_posts = Posts.objects.filter(user__id = request.user.id) #<---add these
context = {
'user':user_profile,
'user_posts':user_posts
}
return render(request,'mainapp/profile.html',context)
A simple class based view for getting a user:
class UserDetailView(DetailView):
model = User
template_name = 'mainapp/profile.html'
context_object_name = 'user'
Relationships (foreign keys) can be followed backwards. Every foreign key has a reverse relationship defined (unless you set reverse_name to +...) it will usually be named <modelname>_set on the model referenced by the foreign key
For example, the following two lines are equivalent
Post.objects.filter(author=user)
user.post_set.all()
This can be used in your profile template
{% for post in user.post_set.all %}
...
{% endfor %}

Form data is not bound in dynamically added inline formset in Django

I got a question regarding the validation of a dynamically added inline formset in Django. It seems like I am missing something in my implementation.
Here is my case:
My project is a team management platform. A team is called Crew and can have several time Schedules. Each Schedule can have several Shifts. Please take a look at my code. At the moment I am able to create a schedule with several, dynamically added forms of the formset for the Shifts, if all fields are valid.
If not, the error for the Shift forms is not displayed and it is filled with the initial data again. It looks like the data of the shift forms is not bound after sending the POST request (because form.is_bound() is false). Moreover the data of Shift forms is not populated again after the POST request.
What do you think is the cause of this behaviour? Do I have to overwrite the is_valid function? I dont know, because it looks like the function works fine - the data is just not bound correctly to the new forms.
Views.py
def schedule_add(request, crew_id):
if request.method == "GET":
form = ScheduleForm()
ShiftFormSet = formset_factory(ShiftForm)
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
elif request.method == "POST":
form = ScheduleForm(request.POST)
numberOfShifts = int(request.POST['form-TOTAL_FORMS'])
ShiftFormSet = formset_factory(ShiftForm, extra=numberOfShifts)
shift_formset = ShiftFormSet(request.POST, prefix='form')
print(request.POST)
if form.is_valid() and shift_formset.is_valid():
schedule = Schedule()
schedule.name = form.cleaned_data.get('name')
schedule.crew = Crew.objects.get(pk=crew_id)
schedule.location = form.cleaned_data.get('location')
schedule.subperiod = form.cleaned_data.get('sub_period')
schedule.save()
for shift_form in shift_formset:
if shift_form.is_valid():
shift = Shift()
shift.min_user_count = shift_form.cleaned_data.get('min_user_count')
shift.max_user_count = shift_form.cleaned_data.get('max_user_count')
shift.start_datetime = shift_form.cleaned_data.get('start_time')
shift.end_datetime = shift_form.cleaned_data.get('end_time')
shift.schedule = schedule
shift.save()
messages.success(request, 'Zeitplan & Schichten angelegt.')
return redirect('shifter:crew_view', crew_id=crew_id)
else:
messages.error(request, 'Fehler')
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
else:
return redirect('shifter:index')
forms.py
class ScheduleForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True, help_text='', label="Name")
sub_period = forms.ModelChoiceField(queryset=SubPeriod.objects.all(), empty_label=None, label="Tag")
location = forms.ModelChoiceField(queryset=Location.objects.all(), empty_label=None, label="Einsatzort")
class Meta:
model = Schedule
fields = ('name', 'sub_period', 'location',)
class ShiftForm(forms.ModelForm):
min_user_count = forms.IntegerField(required=True, help_text='', label="Min Count", initial=2)
max_user_count = forms.IntegerField(required=True, help_text='', label="Max Count", initial=4)
start_time = forms.DateTimeField(required=True, help_text='', label="Shift start", initial=datetime.now)
end_time = forms.DateTimeField(required=True, help_text='', label="Shift end", initial=datetime.now)
class Meta:
model = Shift
fields = ('start_time','end_time','min_user_count','max_user_count',)
Template
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endfor %}
<h2 class="mt-5">Shifts</h2>
<table class="table">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
<th></th>
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% if form.is_bound %}
{% if form.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in form.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
</td>
{% endfor %}
<td></td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">Save</button>
</form>
Thanks in advance,
Christopher
You're returning the class, ShiftFormSet, to the template (in the third-from-last line of your code) instead of the instance, shift_formset.

Checking current user against page they are looking at

I am trying to check the currently logged in user against the user who created the page they are looking at. So essentially, if I am logged in I shouldn't able to go to another user's posts/profile and be able to edit it simply by typing in the edit url pattern.
Here is my view:
class UserEditProfileView(LoginRequiredMixin,UpdateView):
login_url = '/login/'
model = UserProfile
fields = [
'first_name',
'profile_pic',
'location',
'title',
'user_type',
'about',
'website',
'twitter',
'dribbble',
'github'
]
template_name_suffix = '_edit_form'
def qet_queryset(self,request):
current_user = request.user.id
url_args = request.resolver_match.kwargs.pk
if current_user != url_args:
reverse('index')
I have the get_queryset function and the if statement inside it to check if the currently logged in user is the owner of the profile they are trying to edit and redirect them if they aren't. However it is not doing anything... How do I go about implementing this?
Update
View:
class UserEditProfileView(LoginRequiredMixin,UpdateView):
login_url = '/login/'
model = UserProfile
form_class = UserProfileForm
template_name = 'users/userprofile_edit_form.html'
def get_object(self):
return User.objects.get(username=self.request.user.username)
def get_success_url(self):
userid = self.kwargs['pk']
return reverse_lazy('users:user_profile',kwargs={'pk': userid})
urls:
from django.conf.urls import url
from users import views
app_name = 'users'
urlpatterns = [
url(r'^$',views.UserListView.as_view(),name='user_list'),
url(r'^(?P<pk>\d+)/$',views.detailprofile,name='user_profile'),
# url(r'^(?P<pk>\d+)/edit$',views.UserEditProfileView.as_view(),name='user_profile_edit'),
url(
regex=r'^profile/$',
view=views.UserEditProfileView.as_view(),
name='profile'
),
]
Update 2
Userprofile_detail.html Template:
{% extends "base.html" %}
{% block content %}
<div class="sidebar-userinfo">
{% if user.userprofile.profile_pic %}
<img class="profile-pic" src="{{ user.userprofile.profile_pic.url }}">
{% else %}
<img class="profile-pic" src="../../../media/profile_pics/default_pro_pic.png">
{%endif%}
<div class="profile-top-info">
<h2 class="profile-name">{{ user.userprofile.first_name }}</h2>
{% if user.userprofile.location %}
<p class="profile-info small-text">{{ user.userprofile.location }}</p>
{% endif %}
</div>
<div class="profile-info-group">
<p class="accent list-text">Title:</p>
<p class="profile-info list-text">{{ user.userprofile.title }}</p>
<p class="accent list-text">Website:</p>
<p class="profile-info list-text">{{ user.userprofile.website }}</p>
<p class="accent list-text">I'm a:</p>
{% if user.userprofile.user_type == '1' %}
<p class="profile-info list-text">Designer</p>
{% elif user.userprofile.user_type == '2' %}
<p class="profile-info list-text">Developer</p>
{% else %}
<p class="profile-info list-text">Both</p>
{% endif %}
{% if user.userprofile.about %}
<p class="accent list-text">About Me:</p>
<p class="profile-info list-text">{{ user.userprofile.about }}</p>
{% endif %}
<p class="accent list-text">Member Since:</p>
<p class="profile-info list-text">{{ user.userprofile.join_date }}</p>
{% if user.userprofile.twitter %}
<p class="accent list-text">Twitter:</p>
<p class="profile-info list-text">{{ user.userprofile.twitter }}</p>
{% endif %}
{% if user.userprofile.dribbble %}
<p class="accent list-text">Dribbble:</p>
<p class="profile-info list-text">{{ user.userprofile.dribbble }}</p>
{% endif %}
{% if user.userprofile.github %}
<p class="accent list-text">Git Hub:</p>
<p class="profile-info list-text">{{ user.userprofile.github }}</p>
{% endif %}
</div>
{% if request.user.is_authenticated %}
<a class="link" href="{% url 'users:user_profile_edit' %}">Edit Profile</a>
{% endif %}
</div>
<div class="content-right">
{% if user.is_authenticated %}
<a class="btn float-right" href="{% url 'feed:new_post' %}">New Post</a>
{% endif %}
{% include 'feed/userpost_list_inner.html' %}
</div>
{% endblock %}
User profile_edit_form.html template:
{% extends "users/base.html" %}
{% block content %}
<div class="form-title">
<h2 class="form-title-text">Edit Profile</h2>
</div>
<div class="user-forms-base">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input class="btn" type="submit" value="Save" />
</form>
</div>
{% endblock %}
Sam Bobel is right and here is the solution in code for the profile problem:
forms.py:
class UserSettingsForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = [
'first_name',
'profile_pic',
'location',
'title',
'user_type',
'about',
'website',
'twitter',
'dribbble',
'github'
]
urls.py:
urlpatterns = [
url(
regex=r'^profile/$',
view=views.UserEditProfileView.as_view(),
name='profile'
),
]
views.py:
class UserEditProfileView(LoginRequiredMixin, UpdateView):
form_class = UserProfileForm
template_name = 'users/userprofile_edit_form.html'
def get_object(self):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
I would do it a slightly different way. You really don't want those URLs to even exist, because you don't want to tempt the user into changing the number. Instead, I would not pass a PK into the URL at all, and just fetch the current user through overwriting the get_object method to use request.user.id.
See Here for more info
Let me know if clarification would help
You can use a decorator for this. `
def your_decorator(view_func):
def wrapped(request, *args, **kwargs):
.....do your conditions here...if fail redirection takes place here
return view_func(request, *args, **kwargs)
return wrapped
Just use the decorator and it is that simple.

Display a count of Booleans from database

I'm using flask. Database is sqlite3.
In short. I can make lists and I can tick them off as "finished", I want to show the numbers of finished lists in the users profile.
At this time it shows the same as "all lists"..
This is my List model:
class List(Model):
timestamp = DateTimeField(default=datetime.datetime.now)
user = ForeignKeyField(
rel_model=User,
related_name='list'
)
content = TextField()
finished = BooleanField(default=False)
class Meta:
database = DATABASE
order_by = ('-timestamp',)
This is my find finished lists function on the User model:
def finished_lists(self):
return List.select().where(
(List.user == self) |
(List.finished == True)
)
This is the profile template:
{% extends "stream.html" %}
{% block content %}
<div class="row">
<div class="">
<h1>{{ user.username }}</h1>
</div>
<div class="">
<div class="">
<h5>Followers</h5>
<p>{{ user.followers().count() }}</p>
</div>
<div class="">
<h5>Following</h5>
<p>{{ user.following().count() }}</p>
</div>
<div class="">
<h5>Lists</h5>
<p>{{ user.list.count() }}</p>
</div>
<div class="">
<h5>Finished</h5>
<p>{{ user.finished_lists().count() }}</p>
</div>
</div>
<div class="grid-25">
{% if current_user.is_authenticated %}
{% if user != current_user %}
{% if not user in current_user.following() %}
Follow
{% else %}
Unfollow
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
{{ super() }}
{% endblock %}
In your finished list function you select all lists corresponding to the user OR (|) finished . Both conditions should be true to select finished lists so you need and (&)

is_paginated not working for django Generic Views

I've been using django built-in pagination (is_paginated) in few of my pages. They are all working fine. Except for the search page where the pagination should only appear based on the filtered queryset.
I've checked through few other thread but it ain't helping much.
How do I use pagination with Django class based generic ListViews?
Django template tag exception
Here's a mini version of what I have so far:-
1)views.py
class SearchBookView(ListView):
template_name = 'books/search_book.html'
paginate_by = '2'
context_object_name = 'book'
form_class = SearchBookForm
def get(self, request):
form = self.form_class(request.GET or None)
if form.is_valid():
filtered_books = self.get_queryset(form)
context = {
'form' : form,
'book' : filtered_books,
}
else:
context = {'form': form}
return render(request, self.template_name, context)
def get_queryset(self, form):
filtered_books = Book.objects.all()
if form.cleaned_data['title'] != "":
filtered_books = filtered_books.filter(
title__icontains=form.cleaned_data['title'])
return filtered_books
def get_context_data(self):
context = super(SearchBookView, self).get_context_data()
return context
2) search_book.html (template)
{% crispy form %}
{% if book %}
<p>Found {{ book|length }} book{{ book|pluralize }}.</p>
{% for book in book %}
<div class="card">
<div style="height:170px; border:solid #111111;" class="col-md-3">
Ima
</div>
<div class="whole-card col-md-9">
<div class="title">"{{ book.title }}"</div>
<div>{{ book.description }}</div>
Read More
</div>
</div>
{% endfor %}
{% else %}
<p>No book matched your searching criteria.</p>
{% endif %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% endif %}
forms.py
class SearchBookForm(forms.Form):
title = forms.CharField(max_length=20)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.add_input(Submit('search', 'Search', css_class='btn'))
self.helper.form_method = 'GET'
self.helper.layout = Layout('title')
super(SearchBookForm, self).__init__(*args, **kwargs)
------------------UPDATE------------------
Though I understand Daniel Roseman's answer but as I am fairly new to django, I am not sure how to implement the whole thing, hitting plenty of "X not accessible, X is not attribute of Y" and etc. After much digging, I found some other useful posts on this same matter.
Django: Search form in Class Based ListView
Updating context data in FormView form_valid method?
Django CBV: Easy access to url parameters in get_context_data()?
Django class based view ListView with form
URL-parameters and logic in Django class-based views (TemplateView)
Another problem I encounter is I am unable to access the parameters in URL using self.kwargs as what suggested in most of the posts. In the final link I posted above, Ngenator mentioned that URL parameters has to be accessed using request.GET.get('parameter'). I used that and it's working fine for me.
By combining everything, here's the revised piece of coding I have. Just in case anyone is having the same problem as me.
1) views.py
class SearchBookView(ListView):
template_name = 'books/search_book.html'
paginate_by = '3'
context_object_name = 'book_found'
form_class = SearchBookForm
model = Book
def get_queryset(self):
object_list = self.model.objects.all()
title = self.request.GET.get('title', None)
if title is not None and title != "":
object_list = object_list.filter(title__icontains=title)
else:
object_list = []
return object_list
def get_context_data(self):
context = super(SearchBookView, self).get_context_data()
form = self.form_class(self.request.GET or None)
context.update({
'form': form,
})
return context
2) search_book.html (template)
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load staticfiles %}
{% load bootstrap_pagination %}
{% block title %}Search Page{% endblock %}
{% block content %}
<div class="container">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% crispy form %}
{% if book_found %}
<p>Found {{ paginator.count }} book{{ book_found_no|pluralize }}.</p>
{% for book in book_found %}
<div class="wholecard">
<div style="height:170px; border:solid #111111;" class="col-md-3">
Image
</div>
<div class="card col-md-9">
<div class="card-title">"{{ book.title }}"</div>
<div>{{ book.description }}</div>
Read More
</div>
</div>
{% endfor %}
{% else %}
<p>No book matched your searching criteria.</p>
{% endif %}
{% bootstrap_paginate page_obj %}
</div>
{% endblock %}
And I ended up using jmcclell's bootstrap-pagination also for pagination. Saved me lots of time! Good stuff...
You've specifically overridden the get method so that it defines its own context, and never calls the default methods, so naturally none of the default context bars are available.
Don't do that; you should almost never be overriding the get and post methods. You should probably move all the form stuff directly into get_queryset.
It's working
views.py
class UserListView(ListView):
model = User
template_name = 'user_list.html'
context_object_name = 'users'
paginate_by = 10
def get_queryset(self):
return User.objects.all()
templates/user_list.html
{% if is_paginated %}
<nav aria-label="Page navigation conatiner">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li>« PREV </li>
{% else %}
<li class="disabled page-item"><a class="page-link">PREV !</a></li>
{% endif %}
{% for i in %}
{{ i }}
{% endfor %}
{% if page_obj.has_next %}
<li> NEXT »</li>
{% else %}
<li class="disabled page-item"><a class="page-link">NEXT !</a></li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}

Categories

Resources