Django-Filter Form Displaying All Filters? - django-filter

I've just started working with Django Filter. When I test, the filter.form shows filters for all fields and I can't get it to show only the desired filters.
Here's the filter:
class EmployeeFilter(django_filters.FilterSet):
hire_date = django_filters.DateFilter(name='hireDate', lookup_expr='hireDate__year')
hire_date__gte = django_filters.DateFilter(name='hireDate', lookup_expr='hireDate__gte')
hire_date__lte = django_filters.DateFilter(name='hireDate', lookup_expr='hireDate__lte')
class Meta:
model = models.Employee
fields=['hireDate']
Here's the view:
def test_filters(request, template_name='filter-test.html'):
from . import filters
f = filters.EmployeeFilter(request.GET, queryset=models.Employee.objects.all())
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
Has anyone ever run into this? How'd you fix?

I had the same issue but I was able to solve
class EmployeeFilter(django_filters.FilterSet):
class Meta:
model = Employee
fields=['hireDate']
In Views.py
def filters(request):
employee = Employee.objects.all()
myFilter = EmpoyeeFilter(request.GET, queryset=employee)
employee = myFilter.qs
context = {
'myFilter': myFilter,
'employee': employee,
}
return render(request, 'templates/index.html', context)
index.html file
<html>
<form method="get">
{{myFilter.form}}
</form>
</html>

The filter set's form plays both of Django Form's two roles:
It enables you to display the form in your template
It validates the incoming values.
The second of these is (arguably) the more important — certainly for Django Filter: if you remove fields from the form they will not be filtered against.
Your best bet is probably to just define less fields on the filter set. (If you need all fields in some cases just define two filter sets, one for each need.)
(The other option would be to define a separate Django Form with just the fields you need and use that in your template, leaving the filter set's form to do the actual validation.)
I hope that helps.

models.py
class Employee(models.Model):
hire_date = models.DateField()
name = models.CharField(max_length=128)
filters.py
class EmployeeFilter(django_filters.FilterSet):
hire_date = django_filters.DateFilter(field_name='hire_date', lookup_expr='gt')
hire_date__gte = django_filters.DateFilter(field_name='hire_date', lookup_expr='gt')
hire_date__lte = django_filters.DateFilter(field_name='hire_date', lookup_expr='gt')
name__icontains = django_filters.CharFilter(field_name='name', lookup_expr='icontains')
class Meta:
model = Employee
fields = {}
views.py
def employee_view(request):
f = EmployeeFilter(request.GET, queryset=Employee.objects.all())
return render(request, 'product/employee.html', {'filter': f})
templates/my-app/employee.html
<h1>Employee</h1>
<form method="get">
{{ filter.form.as_p }}
<input type="submit"/>
</form>
<ul>
{% for employee in filter.qs %}
{{ employee.hire_date }}<br/>
{% endfor %}
</ul>
The field_name specifies the name of the field in the model ie Employee and lookup_expr is a string which specifies the filter to use on the column of table for eg gt, gte, lt, lte, exact, iexact, contains, icontains

If you want to filter against a field, but do not want it in the form, you can do the following:
import django_filters
from django import forms
class MyFilter(django_filters.FilterSet):
field = django_filters.CharFilter(
widget=forms.HiddenInput()
)
class Meta:
model = MyModel
fields = ['other_field', 'field']
The only downside is, it will show as an empty parameter in the URL, when you submit the form. But it won't affect your results, since its an empty value.

Related

How to get value attribute in views

Hello is there a way to get 'value' attribute from HTML template into views.py and use it there??
HTML:
<form class="card__delete" method="POST"> {% csrf_token %}
<button value="{{item.id}}" class="card__delete__button" name="delete" type="submit">&#10008</button>
</form>
views.py
class TodoView(UserPassesTestMixin, CreateView):
model = Item
template_name = 'home/todo.html'
form_class = ItemCreationForm
def test_func(self):
return self.request.user.username in self.request.path
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['card'] = Card.objects.get(user=self.request.user, pk=self.kwargs.get('pk'))
return context
def post(self, request, pk, username):
if 'delete' in self.request.POST:
Item.objects.get(id=pk).delete()
print('deleted')
return redirect('home-page')
The value is in request.POST, so you should be able to access it with
value = self.request.POST.get('delete', None)
Take care to validate that value before using the id of an object to do anything catastrophic to it (such as .delete()). It's not being validated through a form, and a random hacker on the internet might try posting back random numbers which might be the id of other objects
Added after reading comment:
Data pulled out of request.POST is raw data. I don't think CSRF token can protect against a person who uses inspect object in his browser and changes the value of that button before clicking it. I may be wrong.
Anyway, if you can check the value using a queryset of the object type with a filter for objects that this user is permitted to delete, then do. For example,
value = request.POST.get("delete", None)
if value:
obj = Card.objects.filter(
user=self.request.user ).get( pk=value)
# will raise CardDoesNotExist if value isn't one of user's objects,
# because it's been filtered out
obj.delete()

How can I access my sqlite3 database through the html template using Django?

I have a Django application where most of my backend code is in views.py. In the frontend, I'm using an html template, but currently I have hardcoded options that the user can choose from a drop down menu. Those hardcoded options are all available in the sqlite3 database which is used extensively in views.py. Is there a way that I read those fields of database from the html file directly instead of hardcoding them?
Yes, if you have a model that will store the data from the fields you defined in your template then you can create a form that will store the data about that models fields, then you can just pass the form to the template, for example:
models.py
class Person(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField(default=1)
forms.py
from django import forms
from .models import Person
class PersonForm(forms.ModelForm)
class Meta:
model = Person
fields = '__all__' # or pass an iterable with your model field names as strings
views.py
from .models import Person
from .forms import PersonForm
def create_person(request):
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
person = form.save() # creates and saves a new Person instance
return redirect('person', pk=person.pk) # redirect to the view that displays the person
else:
form = PersonForm()
return render(request, 'create_person.html', {'form': form}) # pass the form to the view in a context dictionary
def person(request, pk): # pass the primary key of a person to the view
person = Person.objects.get(pk=pk)
return render(request, 'person.html', {'person': person})
create_person.html ( this is the view that will have the form )
<form method="post">
{% csrf_token %}
{{ form.as_p }} <!-- render form fields inside <p> tags ( you can also use table or list ) -->
<button type="submit" value="Save"></button>
</form>
person.html
<p>This is the page that belongs to the {{ person.name }}</p>
<p>The {{ person.name }} is {{ person.age }} years old.</p>
And finally set up the urls.py for your views:
from django.urls import path
from . import views
urlpatterns = [
path('create_person', views.create_person, name="create_person"),
path('person/<int:pk>/', views.person, name="person") # pass the pk argument into the url path here
]

Can't call model to Django template

I'm trying to call an attribute from my model into my HTML template using Django. There is something strange going on as I am only able to call one of my two models into the template. Both models are working perfectly fine as far as I can tell by looking into my database. This is what my models.py looks like
class Respondez(models.Model):
responder = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='scores')
score = models.IntegerField(default=0)
post_time = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ['post_time']
def __str__(self):
return self.score
class Profilez(models.Model):
newuser = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True,null=True)
preference = models.CharField(max_length=30)
def __str__(self):
return self.newuser
I am trying to call Profilez. However, only Respondez can be called. This is the view I'm calling from, which I simplified.
#login_required
def add(request):
p = Profilez()
z = Respondez()
context = {
'p' : p,
'z' : z
}
return render(request, 'rating/add.html', context)
To test whether I can call my models, I have simple header tags in HTML for my template, add.html:
{% extends "rating/base.html" %}
{% block content%}
<h3> {{user.username}} </h3>
<h3> {{ z.post_time }}</h3>
<h3>{{ p.preference }}</h3>
No matter which attribute I call from the models, the line for Respondez works but nothing works for my Profilez model. This is despite the fact that my database has values saved for each attribute from both models.
I am getting inputs for preference from the following view on a separate template (first line won't paste with correct indentation), where users select 1 of 2 choices:
def onboarding2(request):
p = Prof()
p.newuser = request.user
if request.method == 'POST':
selected_opt = (request.POST['ob'])
if selected_opt == 'mood':
p.preference = 'mood'
elif selected_opt == 'productivity':
p.preference = 'productivity'
else:
return HttpResponse(400, 'Invalid form')
p.save()
return redirect('rating-onboarding3')
context = {
'p' : p,
}
return render(request, 'rating/onboard2.html', context)
How can I accurately call my Profilez model? What's wrong here?
Since you have instantiated Profilez with no parameters in the constructor, none of its fields get the initial value. Hence, p.preference also happens to be null. That is why p.preference is not visible in the template.
But, in case of Respondez, though you are still instantiating the object with no parameters, you still have given the default value of current time to z.post_time, so z.post_time is working.
If you want to access p.preference, you need to explicitly assign some value to p.preference, else how will the template show the value for something that doesn't have a value initialized in the first place? For instance, you could do p = Profilez(preference='xyz') while creating the object, and see what happens.
Also, if you want to fetch a specific entry from the database, then you need to do a query, rather than creating a new object. The syntax for creating query would be something like Profilez.objects.get(newuser=some_random_user).

Django how to ManyToManyField show in template as Select widget

My models.py:
class Model2(models.Model)
choice_field = models.ManyToManyField(to=Model)
my views.py:
def func(request):
if request.method == 'POST':
form = ModelForm(request.POST)
if form.is_valid:
form.save()
return.........................................
And so what I need to do with form request?
my template.html:
<div>
{{ form.choice_field }}
</div>
I get a values list and can a scroll and choose what I want. But i want to use Select with options for this values in template.
You can define widget for each field of your model manually. Assuming you using built-in ModelForm your code in forms.py can be something like this:
from django.forms import ModelForm, Select
class Model2Form(ModelForm):
class Meta:
model = Model2
fields = [
'choice_field',
]
widgets = {
'choice_field': Select(),
}

Django form performance

I asked this in Code Review but it was rejected with a cause of "broken code." That is why I'm asking it here. This site is probably more appropriate for this question than the Code Review one.
In my app, a user can modify a course that they created. One field is a "teacher" field and the user can select a different person to be the teacher. This ForeignKey creates 138 duplicated queries and I can't figure out how to make it more efficient.
Model:
class CourseCatalog(models.Model):
course_name = models.CharField(verbose_name="Course name", max_length=50)
course_desc = models.TextField(verbose_name="Course Description")
teacher = models.ForeignKey(Teacher, blank=True, null=True,
verbose_name='Course Owner', on_delete=models.PROTECT)
...
View:
class EditCourseCatalog(UpdateView):
model = CourseCatalog
fields = ['course_name','course_desc', 'teacher']
template_name = 'school/course_catalog/new_edit_form.html'
Template:
...
<h3>Course Form</h3>
{{ user.teacher }}
<form action="" method="post">{% csrf_token %}
{{form|crispy}}
...
Here is the query from debug that is duplicated 138 times. The only difference between the queries is the school_familymember.id = 220.
SELECT `school_familymember`.`id`, `school_familymember`.`password`,
school_familymember.last_login, school_familymember.is_superuser,
school_familymember.username, school_familymember.first_name,
school_familymember.last_name, school_familymember.email.school_familymember.is_staff, school_familymember.is_active, school_familymember.date_joined, school_familymember.family_id, school_familymember.middle_name, school_familymember.family_member_role_id, school_familymember.address1, school_familymember.address2, school_familymember.city, school_familymember.state, school_familymember.zip_code, school_familymember.notes, school_familymember.gender, school_familymember.phone_number, school_familymember.cell_phone_number FROM school_familymember WHERE school_familymember.id = 220
The Teacher model is also a foreign key to the FamilyMember table and this is where I think I'm having the issue. I'm wondering if there is a way to make one single query to collect the family names and ids and then use that for the drop down list in the form. Can I do this with the built in form managers or do I have to scrap that and create the queries in the view and pass them to the form?
class Teacher(models.Model):
family_member = models.OneToOneField(FamilyMember, verbose_name='name')
notes = models.TextField(blank=True)
Create a custom model form, and in the __init__ method change the teachers queryset to use select_related to be more efficient.
class CourseCatalogForm(forms.ModelForm):
class Meta:
fields = ['course_name','course_desc', 'teacher']
def __init__(self, *args, **kwargs):
super(CourseCatalogForm, self).__init__(*args, **kwargs)
self.fields['teacher'].queryset = self.fields['teacher'].queryset.select_related('family_member')
Then use your new model form class in your view instead of specifying fields.
class EditCourseCatalog(UpdateView):
model = CourseCatalog
template_name = 'school/course_catalog/new_edit_form.html'
form_class = CourseCatalogForm