【问题标题】:Django reverse foreign key in adminDjango在admin中反向外键
【发布时间】:2014-06-19 04:07:45
【问题描述】:

我在管理面板中有一个关于外键的 Django 相关问题。我面临以下情况:

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)

每个设备都需要有一个绑定的驱动程序(它使用它)。 DriverAssignment 应该是显示哪个驱动程序可以被哪个设备使用的表。所以一个设备可以有多种可以绑定的驱动程序的可能性。现在我想在我的管理面板上有一个下拉列表,显示特定设备的所有可能驱动程序以选择“bound_driver”。

我如何在 Django 中做到这一点?对于一个有经验的 Django 人来说,这可能是一件容易的事。我希望有人能给我一个提示,因为我是 Django 的新手。非常感谢!

【问题讨论】:

  • 我猜 ManyToManyField 是您正在寻找的答案。 docs.djangoproject.com/en/1.6/ref/models/fields/…
  • 如果我错了,请纠正我。我认为这只会摆脱 DriverAssignment 模型(因为它将自动创建一个连接表)但是我如何在管理页面上显示它?如何让用户选择与设备具有多对多关系的驱动程序?非常感谢您的回答!

标签: python django django-models django-admin


【解决方案1】:

将您的模型结构更改为:

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 的作用与 DriverAssignment Table 相同。

您可以在可用驱动程序字段中添加可用驱动程序。

但您还希望 bound_driver 是可用驱动程序之一。您必须在表单中进行此验证。为此,您必须覆盖管理表单。查看链接

参考链接:

多对多字段https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.ManyToManyField

模型管理员(覆盖管理员功能)https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-objects

如果您想了解更多信息,则必须花一些时间阅读和实施。 :)

如果你想使用相同的结构,那么你将不得不覆盖ModelAdmin 中的form 请参阅here 并为您提供自定义表单,如下所示:

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

【讨论】:

  • 在管理面板中有一个下拉菜单,这样用户只能选择一个有效的“boud_driver”不是更好吗?这样我就不需要表单验证,而且更加用户友好。
  • 是的,您可以这样做,但为此您也必须覆盖管理员使用的 ModelForm,以提供自定义查询集。见:docs.djangoproject.com/en/1.6/ref/contrib/admin/…
【解决方案2】:

有一个用于反向内联的 sn-p。如果你仍然需要它,你可以试试这个: https://gist.github.com/mzbyszewska/8b6afc312b024832aa85

我已将它用于 django 1.5 和 1.6 中的 OneToOneField。不幸的是,我没有为 ForeignKeyField 测试它,但之前的一位用户声称它也适用于 ForeignKeyField。

对sn-p的最佳描述包含在其中。 Person 类是您的 DriverAssignment 类,Device 对应于下例中的 Address 类:

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.

【讨论】:

    【解决方案3】:

    对于 Django >1.8

    使用InlineModelAdmin(2.2 的文档),如那里所述:

    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,
        ]
    

    【讨论】:

    • 做得很好,从第一次尝试就成功了,正是我想要的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    • 2013-02-24
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    相关资源
    最近更新 更多