Question

I have a Django related question about foreign keys in the admin panel. I'm facing the following situation:

class Driver(models.Model):
    name = models.CharField(max_length=200)
    executable = models.CharField(max_length=200)

class Device(models.Model):
    name = models.CharField(max_length=200)
    bound_driver = models.ForeignKey(Driver)

class DriverAssignment(models.Model):
    device = models.ForeignKey(Device)
    driver = models.ForeignKey(Driver)

Every device needs to have a bound driver (which it uses). DriverAssignment should be the table which shows which driver can be used by which device. So one device can have multiple possibilities of drivers which can be bound. Now i would like to have a dropdown on my admin panel showing all possible drivers for a specific device to select the 'bound_driver'.

How can i do this in Django? This is probably an easy thing for an experienced Django guy. I hope someone can give me a hint since i'm kind of new to Django. Thanks a lot!

Était-ce utile?

La solution 2

Change your model Structure to This:

class Driver(models.Model):
    name = models.CharField(max_length=200)
    executable = models.CharField(max_length=200)

class Device(models.Model):
    name = models.CharField(max_length=200)
    bound_driver = models.ForeignKey(Driver, related_name="bound_to")
    available_drivers = models.ManyToManyfield(Driver)

ManyToManyField would do the same work as DriverAssignment Table.

You can add Available drivers in Available drivers field.

But then You would also Want that bound_driver is one of the Available Drivers. This validation you will have to do in forms. For that you have to over-ride Admin forms. See links

Links of Reference:

ManytoMany field: https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.ManyToManyField

Model Admin (to over-ride admin functionality): https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-objects

You will have to spend some time reading and implementing if you want ot learn more. :)

OR

If you want to go with the same structure, than you will have to over-ride the form in ModelAdmin see here and Provide you custom form, which will be something like this:

class CustomForm(ModelForm)
  bound_driver = forms.ModelChoiceField(queryset = <your custom queryset that returns only available drivers>, ...)
  class Meta:
    model = Device

https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form

Autres conseils

For Django >1.8

Use the InlineModelAdmin (docs for 2.2) as explained there:

models.py

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author, on_delete=models.CASCADE)
   title = models.CharField(max_length=100)

admin.py

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

There is a snippet for inverse inlines. If you still need it you may try this: https://gist.github.com/mzbyszewska/8b6afc312b024832aa85

It has been used by me for OneToOneField in django 1.5 and 1.6. Unfortunately I did not test it for ForeignKeyField, but the one of the previous users claims that it works for ForeignKeyField either.

The best description of the snippet is contained in it. The Person class is your DriverAssignment class and Device correspond to the Address class in the example below:

Example:

    from django.db import models
    class Address(models.Model):
        street = models.CharField(max_length = 255)
        zipcode = models.CharField(max_length = 10)
        city = models.CharField(max_length = 255)
    class Person(models.Model):
        name = models.CharField(max_length = 255)
        business_addr = models.ForeignKey(Address,
                                             related_name = 'business_addr')
        home_addr = models.OneToOneField(Address, related_name = 'home_addr')
        other_addr = models.OneToOneField(Address, related_name = 'other_addr')



You use reverseadmin in the following way:

    from django.contrib import admin
    from django.db import models
    from models import Person
    from reverseadmin import ReverseModelAdmin
    class AddressForm(models.Form):
        pass
    class PersonAdmin(ReverseModelAdmin):
        inline_type = 'tabular'
        inline_reverse = ('business_addr', ('home_addr', AddressForm), ('other_addr' (
            'form': OtherForm
            'exclude': ()
        )))
    admin.site.register(Person, PersonAdmin)

inline_type can be either "tabular" or "stacked" for tabular and
stacked inlines respectively.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top