I am trying to customise the Django admin add/change for a project. I have created a model called "Visit" which contains 3 Foreign Key fields: "Customer", "Pet" and "Doctor". The workflow is as follows:
Below is the code for my models.py
class Visit(models.Model):
customer = models.ForeignKey('customer.Customer', on_delete=models.CASCADE)
pet = models.ForeignKey('pet.Pet', on_delete=models.CASCADE)
date = models.DateTimeField()
doctor = models.ForeignKey(
'configuration.Doctor', on_delete=models.DO_NOTHING, null=True, blank=True)
status = models.CharField(
choices=PET_STATUS, max_length=3, null=True, blank=True)
reason = models.CharField(max_length=255)
diagnosis = models.TextField(null=True, blank=True)
treatment = models.TextField(null=True, blank=True)
comment = models.TextField(null=True, blank=True)
prescription = models.TextField(null=True, blank=True)
weight = models.DecimalField(
max_digits=6, decimal_places=2, null=True, blank=True)
class Meta:
ordering = ('-date',)
My issue is that someone using the Django Admin to create a Visit can wrongly choose a Customer and Pet. Hence, the Customer does not own that Pet. I would like to know how can I customise the Django Admin, so that, when the user selects a Customer, only Pets under that particular Customer is displayed in the selectbox.
Below is my admin.py
class VisitAdmin(admin.ModelAdmin):
change_form_template = 'visit/invoice_button.html'
add_form_template = 'visit/add_visit.html'
list_display = ('customer', 'pet', 'date', 'status')
list_filter = ('date', 'customer', 'pet', 'status')
search_fields = ('customer__first_name',
'customer__last_name', 'pet__pet_name')
autocomplete_fields = ['customer', 'pet', 'doctor']
radio_fields = {'status': admin.HORIZONTAL}
fieldsets = (
(None, {
"fields": ('customer', 'pet', 'doctor'),
}),
("Visit Details", {
"fields": ('date', 'reason', 'weight', 'status'),
}),
("Visit Outcome", {
"fields": ('diagnosis', 'treatment', 'comment')
})
)
inlines = [FeeInLine, AttachmentInLine]
actions = ['export_as_csv']
def export_as_csv(self, request, queryset):
meta = self.model._meta
field_names = [field.name for field in meta.fields]
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={}.csv'.format(
meta)
writer = csv.writer(response)
writer.writerow(field_names)
for obj in queryset:
row = writer.writerow([getattr(obj, field)
for field in field_names])
return response
export_as_csv.short_description = "Export Selected"
def response_change(self, request, obj):
if "invoice" in request.POST:
return render_pdf(request, obj.pk)
return super().response_change(request, obj)
admin.site.register(Visit, VisitAdmin)
i faced the same issue, in my case i use raw_id_field
for my foreign keys and many to many fields in ModelAdmin And override add and change template.
you can use raw_id_field
for forign keys and in your templates write javascript to change href
of search icon for Pet
foreign key field when Customer
id field changed, and in href
use url lookup to show only Pet
which belongs to selected Customer
# stock/models.py
class Category(models.Model):
title = models.CharField(max_length=255, blank=True)
is_active = models.BooleanField(default=True)
class Product(models.Model):
category = models.ForeignKey(
Category, on_delete=models.PROTECT, related_name="product"
)
feature_option = models.ManyToManyField("FeatureOption", blank=True, related_name="product")
class Feature(models.Model):
title = models.CharField(max_length=255, blank=True)
category = models.ManyToManyField(Category, blank=True, related_name="feature")
class FeatureOption(models.Model):
title = models.CharField(max_length=255, blank=True)
feature = models.ForeignKey(
Feature, on_delete=models.CASCADE, related_name="feature_option"
)
# stock/admin.py
class CategoryAdmin(admin.ModelAdmin):
raw_id_fields = ['parent']
class ProductAdmin(admin.ModelAdmin):
add_form_template = 'admin/product_add_form.html'
change_form_template = 'admin/product_change_form.html'
raw_id_fields = ['category', "feature_option"]
class FeatureOptionAdmin(admin.ModelAdmin):
list_filter = (("feature__category", admin.RelatedOnlyFieldListFilter),)
and in my template i use javascript to change the href
of FeatureOption
search icon for url lookup
<!-- product_add_form.html -->
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block admin_change_form_document_ready %} {{ block.super }}
<script lang="text/javascript">
function changeFeatureOptionPopupUrl() {
const featureOptionBaseUrl = "/admin/stock/featureoption/";
let categoryTextBox = document.getElementById("id_category");
document.getElementById("lookup_id_feature_option").href = featureOptionBaseUrl + "?feature__category__id__exact=" + categoryTextBox.value;
}
document.getElementById("lookup_id_feature_option").onfocus = function () {changeFeatureOptionPopupUrl()}
</script>
{% endblock %}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.