Code

Opened 6 years ago

Closed 6 years ago

Last modified 3 years ago

#7918 closed (fixed)

Allow ForeignKey to a parent class when using inlines

Reported by: sil Owned by: brosner
Component: Database layer (models, ORM) Version: master
Severity: Keywords:
Cc: arnaud.rebts@… Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: yes Patch needs improvement: no
Easy pickings: UI/UX:

Description (last modified by brosner)

At the moment, if you have a hierarchy:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()
    serves_pizza = models.BooleanField()

(as per http://www.djangoproject.com/documentation/model-api/#multi-table-inheritance), it doesn't interact all that well with inlined ForeignKeyed models. Imagine you had:

class Owner:
    name = models.CharField(max_length=100)
    place = models.ForeignKey(Place)

(so a Place can have multiple Owners). This also works fine with Restaurants, because every Restaurant is-a Place. However, if you want to inline the Owners:

class OwnerInline(admin.TabularInline): 
    model = Owner
    extra = 5

class PlaceAdmin(admin.ModelAdmin):
    model = Place
    inlines = [OwnerInline]

then this won't work; if you try and create a Restaurant, you get a complaint that Owner has no ForeignKey to Restaurant (because technically it doesn't). This is because (new)forms._get_foreign_key checks that the ForeignKey points to this model itself, where it should really be checking whether the ForeignKey points to this model or any of its ancestor classes. The attached patch rectifies this.

Attachments (1)

subclass-foreignkey.patch (1.3 KB) - added by sil 6 years ago.
Updated to handle fail

Download all attachments as: .zip

Change History (16)

comment:1 Changed 6 years ago by sil

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

mrph. Code from above in code formatting. Sorry.

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()
    serves_pizza = models.BooleanField?()

class Owner:
    name = models.CharField(max_length=100)
    place = models.ForeignKey(Place)

class OwnerInline(admin.TabularInline):
    model = Owner
    extra = 5

class PlaceAdmin(admin.ModelAdmin):
    model = Place
    inlines = [OwnerInline]

comment:2 Changed 6 years ago by sil

  • Needs documentation set
  • Needs tests set
  • Patch needs improvement set

comment:3 Changed 6 years ago by brosner

  • Description modified (diff)

Fixed ticket description formatting.

comment:4 Changed 6 years ago by brosner

  • Owner changed from nobody to brosner
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Accepted
  • Version changed from newforms-admin to SVN

comment:5 Changed 6 years ago by brosner

  • milestone set to 1.0 beta

Changed 6 years ago by sil

Updated to handle fail

comment:6 Changed 6 years ago by sil

Updated patch to handle the OneToOneField value being null when you're first adding a Restaurant, which blows up because it's not a nullable field (since it's a PK) but doesn't have a value (because the Restaurant isn't saved yet). Sorry.

comment:7 Changed 6 years ago by sil

  • Patch needs improvement unset
  • Triage Stage changed from Accepted to Unreviewed

comment:8 Changed 6 years ago by brosner

  • Triage Stage changed from Unreviewed to Accepted

Don't change the stage. That is reserved for ticket triagers and committers. The ticket itself is accepted, you don't need to do that when you upload a new patch. The needs_better_patch is meant for that :)

comment:9 Changed 6 years ago by sil

Cool -- I figured that the newer patch wasn't reviewed :) no problem!

comment:10 Changed 6 years ago by brosner

It is likely [8165] has fixed this. Can someone verify? Perhaps a test case should be ordered :)

comment:11 Changed 6 years ago by brosner

  • milestone changed from 1.0 beta to 1.0

comment:12 Changed 6 years ago by Arnaud Rebts

  • Cc arnaud.rebts@… added

It seems to be working now if the ForeinKey is in the direct super class, but not if it's in a higher class.

So, this is working:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()
    serves_pizza = models.BooleanField()

class Owner(models.Model):
    name = models.CharField(max_length=100)
    place = models.ForeignKey(Place)

class OwnerInline(admin.TabularInline): 
    model = Owner
    extra = 5

class PlaceAdmin(admin.ModelAdmin):
    model = Place
    inlines = [OwnerInline]

class RestaurantAdmin(admin.ModelAdmin):
    model = Restaurant
    inlines = [OwnerInline]

But not this:

class ItalianRestaurant(Restaurant):
    pass

class ItalianRestaurantAdmin(admin.ModelAdmin):
    model = ItalianRestaurant
    inlines = [OwnerInline]

comment:13 Changed 6 years ago by jacob

  • Component changed from Uncategorized to Database wrapper

comment:14 Changed 6 years ago by brosner

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [8708]) Fixed #7918 -- Allow the foreign key in an inline to be any where in the parent chain. Thanks sil for the report.

comment:15 Changed 3 years ago by jacob

  • milestone 1.0 deleted

Milestone 1.0 deleted

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.