Admin Forms Show Multiple Fields from Foreign Key Model

Hello All,

My knowledge of django is less than a week old, so I’m sure my question is out of my pure inability to process enough information quickly enough…

I am building a bus/vehicle fleet management system for the school that I work at. I understand how to and have implemented the one to many relationships from my primary fleet model to several other models using foreign keys (engine type, fuel type, chassis, etc…), but these have all been models that only needed 1 field.

I am trying to do this all in the admin interface because it is just sooo good, and feels very comfortable, but I may have hit a snag…

I am now to the workorder model, which should also be a many to one relationship. There should be one vehicle (from the fleet model) assigned to each of the workorders contained within the workorder model. This relationship makes just as much sense as the others, but I don’t understand how to fully incorporate the fields from this workorder model into the fieldset of my fleet model. At the moment, I have just the singular foreignkey field, which acts as a selector, just like the other ones, but I also need to be able to modify other elements of the workorder model, preferably both inside of the workorder model directly and within the fleet model.

I thought I could pull this off using the related_names tool, but, while I can add multiple foreignkeys to the same model that way, they just seem to point at the same select option. I haven’t been able to figure out how to phrase my question well enough for Google to help me out:

Is it possible to point to a specific field of a model when it is called using the foreignkey fieldtype? If so, how would I go about doing that?

For clarification, I have the following two models:
Fleet

class Fleet(models.Model):
    name = models.CharField(max_length=100)
    active = models.BooleanField()
    plate = models.CharField(max_length=20, blank=True, null=True)
    vin = models.CharField(max_length=17, blank=True, null=True)
    workorder = models.ForeignKey('Workorders', on_delete=models.SET_NULL, blank=True, null=True)

And Workorders

class Workorders(models.Model):
    unit = models.ForeignKey(Fleet, on_delete=models.DO_NOTHING, blank=False, null=False, related_name='unit', verbose_name='Vehicle')
    vin = models.ForeignKey(Fleet, on_delete=models.SET_NULL, blank=True, null=True, related_name='vin_number')
    description = models.TextField(blank=True, null=True, verbose_name='Problem/Description')

I’ve removed several of the other fields for the sake of easier reading…

I guess my questions are as follows:

  1. How would I pull both the unit and the description fields from Workorders into a Fleet fieldset?
  2. Is there a way to automatically populate the other foreignkey values of the same model with the information from the model they are referencing? For example, when a user selects a unit on the Workorders form (from either the Fleet fieldset or the Workorders Modle), can the vin field be autopopulated? Maybe even as readonly?

Very sorry for the questions this early in my django adventure. Hopefully this is clear enough to be pointed in the correct direction.

Thanks for your time!

To achieve the first one you can make use of Django’s inline formsets and customize the Django admin interface like this in admin.py

from django.contrib import admin
from django.forms import BaseInlineFormSet
from .models import Fleet, Workorders

class WorkorderInlineFormset(BaseInlineFormSet):
    model = Workorders
    fields = ['unit', 'description']  # Specify the fields you want to include

class WorkorderInline(admin.StackedInline):
    model = Workorders
    formset = WorkorderInlineFormset
    extra = 1

@admin.register(Fleet)
class FleetAdmin(admin.ModelAdmin):
    inlines = [WorkorderInline]
    list_display = ['name', 'active', 'plate', 'vin']

And for the second one I don’t have the exact idea :neutral_face:.

1 Like

I am curious - in the Workorders model, are unit and vin referring to the same Fleet object? Or can they be references to two different objects?

Also, when modeling data, the generally accepted practice is that the models are named for the singular and not plural. (That’s an old convention going back to the very early days of relational modeling.) So I would suggest your models would be better named as WorkOrder and Vehicle.

This got me going on the right track for the first question. I did have to remove the WorkorderInlineFormset portion. For whatever reason, the fields setting wasn’t working there. I did this instead and removed the previous block entirely.

class WorkorderInline(admin.TabularInline):
    model = Workorders
    #formset = WorkorderInlineFormset
    fields = ('wo_number', 'description')
    readonly_fields = ('wo_number',)
    fk_name = 'unit'
    extra = 0
    template = 'admin/edit_inline/workorders.html'
    show_change_link = True
    show_url = True

Hello!

No, unit would refer to vehicle and vin would refer to vin. That is actually more of what my question is. I have no idea how to make them point to anything other than the first object listed in the Fleet model.

Also, I read that in a couple of posts, so I had planned to go back and rename soon. I was mostly making sure I could get the base functionality while learning. I’ve made several of those mistakes that go against best practice, and I have a fair bit of cleaning up to do! Thanks for putting that information in one place though!

This statement doesn’t make sense to me. Both are foreign keys to the Fleet model.

They either both point to the same instance of Fleet, or they can point to different ones. They are a reference to an instance of Fleet, not a field within that model.

Even more confusingly, you have a workorder field in Fleet that refers back to Workorders.

I think you may need to take a step back and really rethink your data models here.

Is an instance of Fleet supposed to be a single vehicle? (It would seem that way because of the plate and vin fields.)

Is a Workorder a reference to some work that needs to be done? Does that Workorder refer to work to be done on one vehicle only, or can it refer to the same work being done on multiple vehicles?

Apologies. I misunderstood the terminology.

So an instance of Fleet is holding one vehicle and only ever one vehicle A workorder should allow to point to either a singular vehicle or to be a “disconnected” workorder, as more of a general set of tasks. This second option would be far less commonly used if ever. I know I need to modiby the blank and null arguments in the unit portion.

Yes, the workorders foreign key within the ``Fleet``` model was when I was trying to figure out how to get the fields from workorders to display in the fleet fieldset. Since I’m now using the inline form, I don’t need that anymore.

I understand how these items would connect on a flowchart. Translating that into a relational database while also trying to figure out how django interacts with that database is where I got stuck.

No apolgies necessary - we’re here to help.

If a WorkOrder refers to 0 or 1 Fleet, then there should be one FK from WorkOrder to Fleet. You then define that field with blank and null True.

Actually, that’s frequently considered to be looking at this from the wrong direction. You’re usually better off identifying your data entities first - ensuring you understand the relationship among them. Once you’ve got that done - and assuming you’ve done it correctly - you’ll find that your processing flows fall quite naturally from that. (And, if you’ve defined your data well, you’ll discover that it’s extremely flexible and you can easily add additional functionality with few problems.)

Thanks for that.

I think another part of my issue is stemming from the fact that I’m not building this from scratch. There is an old program that we are currently using, and the developer just disappeared. For compliance, we are going to have to move to a new system. I was able to open that database, so I’ve been trying basically duplicate the structure and relationships. I suppose it is fair to think that the original structure might not have been the most efficient, so directly copying it could result in the same or different errors.

I guess a practical “is this possible” sort of question before I move further down the rabbit hole:
For the workorder inline form, can I display other elements from the connected fleet object?

For example, when I open the workorder model within the admin change form, can I have readonly fields that are populated with the vin and plate of the vehicle the workorder is related to?

Yes. You would need to create a model method in Workorder to return those fields, but then you can reference those methods in your ModelAdmin.readonly_fields for workorder.

Thanks to both of you! I ended up ding this in the Workorders model (soon to be renamed):

class Workorders(models.Model):
    wo_number = models.AutoField(primary_key=True, verbose_name='Workorder Number')
    unit = models.ForeignKey(Fleet, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name='Vehicle')
    description = models.TextField(blank=True, null=True, verbose_name='Problem/Description')

    @property
    def vin(self):
        if self.unit:
            return self.unit.vin
        return None

This seems to work quite well after adding it to the readonly fields in admin.py.

I’m not sure how to mark both answers as the solution. To tro and be a fair as possible, I went ahead and marked @addwebsolution as being the solution since Ken has just a couple more solutions to his account. Seriously though, I appreciate the help and the patience!