提问人:Tachyon6 提问时间:11/4/2023 更新时间:11/19/2023 访问量:122
Django Admin 中的外键日期范围过滤
foreign key daterange filtering in django admin
问:
对于使用 django admin 的酒店预订系统,我想过滤给定日期范围内的可用房间,模型如下
class Room(models.Model):
id = models.AutoField(primary_key=True)
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
class Booking(models.Model):
id = models.AutoField(primary_key=True)
start_date = models.DateField(verbose_name=_("Start date"))
end_date = models.DateField(verbose_name=_("End date"))
room = models.ForeignKey(Room, on_delete=models.CASCADE)
如何在后台中筛选房间,以便选择日期范围并仅返回所选范围内没有预订的房间?
多谢
答:
1赞
inquirer
11/6/2023
#1
为了传递范围数据,我在管理员中创建了一个表单。为此,我覆盖了 .该模板将添加到以下目录中:。admin/change_list.html template
change_list.html
templates/admin
我尝试仅使用 Django 进行过滤,例如:
response.context_data['cl'].result_list = (
Room.objects.filter(~Q(booking__end_date__range=val) &
~Q(booking__start_date__range=val)))
但结果并不完全正确。
我认为需要从每个预订记录创建一个日期范围,并将其与从表单日期创建的范围进行比较。Pandas 非常适合此目的。 使用以下方法:date_range、isin、loc。
admin.py
import pandas as pd
from django.contrib import admin
from .forms import TestForm
from .models import *
class Room_Admin(admin.ModelAdmin):
list_display = ('id', 'hotel')
change_list_template = 'admin/change_list.html'
def changelist_view(self, request, extra_context=None):
response = super().changelist_view(
request,
extra_context=extra_context,
)
if request.method != 'POST':
response.context_data['form'] = TestForm()
else:
form = TestForm(request.POST)
if form.is_valid():
response.context_data['form'] = form
# Getting the start and end from the form
val = [form.cleaned_data.get('start'), form.cleaned_data.get('end')]
bkg = Booking.objects.values('start_date', 'end_date', 'room')
# Create a list based on form dates from and to
custom_range = pd.date_range(start=val[0], end=val[1])
df = pd.DataFrame(bkg)
def f(x):
abc = pd.date_range(
start=df.loc[x, 'start_date'], end=df.loc[x, 'end_date']
).isin(custom_range)
return ~abc.any()
# List of rooms based on the secondary Booking model whose
# dates do not intersect with custom_range dates
room = [df.loc[i, 'room'] for i in range(len(df)) if f(i)]
# room numbers that are not booked at all
no_booking = [i.id for i in Room.objects.all() if len(i.booking_set.all()) < 1]
room = room + no_booking
response.context_data['cl'].result_list = Room.objects.filter(id__in=room)
return super(Room_Admin, self).changelist_view(request, extra_context=response.context_data)
return response
admin.site.register(Room, Room_Admin)
forms.py
class TestForm(forms.Form):
start = forms.DateField(widget=forms.SelectDateWidget(years=range(2022, 2025)))
end = forms.DateField(widget=forms.SelectDateWidget(years=range(2022, 2025)))
模板
{% extends 'admin/change_list.html' %}
{% block result_list %}
<form action='' method='POST'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='adding'/>
</form>
{{block.super}}
{% endblock %}
评论