I need some help with an issue that I am not able to resolve on my own. So in this model, a tenancy document can either have a ForeignKey with Building or Property.
We may have a tenancy agreement on the whole building or on a single property within that building. In the former case the tenancy documents are applied to the building, and in the latter case they only apply to a property.
I used content_types to add a generic foreign key but now I can’t figure out how to add autocomplete fields to contenttype and in the dropdown, I just see building and property in admin form. I want to see building names and property names.
I learned about autocomplete fields in Django 2.0, it’s awesome but I don’t know how can I use something like that in this particular case or if there is a better way to do this?
models.py:
class TenancyDocument(models.Model):
KINDS = Choices('Tenancy Agreement', 'Stamp Duty', 'Inventory List')
id = FlaxId(primary_key=True)
kind = StatusField(choices_name='KINDS')
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
content_type_limit = Q(
app_label='properties', model='building') | Q(
app_label='properties', model='property')
content_type = models.ForeignKey(
ContentType,
limit_choices_to=content_type_limit,
on_delete=models.CASCADE,
verbose_name='Lease type'
)
object_id = FlaxId(blank=True, null=True)
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
return self.kind
admin.py:
@admin.register(TenancyDocument)
class TenancyDocumentAdmin(admin.ModelAdmin):
list_display = ('id', 'kind', 'start_date', 'end_date','content_type')
list_filter = ('kind',)
It seems like the generic foreign key has always been more trouble than it's worth. It takes a simple concept, a relational join, and tries to make it clever, but then downstream packages like autocomplete won't work.
I ended up switching to two separate foreign keys, then added attributes to the class to pull fields from the correct related record.
class TenancyDocument(models.Model):
building = models.ForeignKey(Building, ondelete='CASCADE', null=True, blank=True)
prop = models.ForeignKey(Property, ondelete='CASCADE', null=True, blank=True)
def clean(self):
if not self.building and not self.prop:
raise ValidationError('Must provide either building or property.')
if self.building and self.prop:
raise ValidationError('Select building or property, but not both.')
super().clean()