24π
If you think the link app will always point to a single app then one approach would be to pass the name of the foreign model as a string containing the application label instead of a class reference (Django docs explanation).
In other words, instead of:
class Link(models.Model):
blog_post = models.ForeignKey(BlogPost)
do:
from django.conf import setings
class Link(models.Model):
link_model = models.ForeignKey(settings.LINK_MODEL)
and in your settings.py:
LINK_MODEL = 'someproject.somemodel'
2π
I think TokenMacGuy is on the right track. I would look at how django-tagging handles a similar generic relationship using the content type, generic object_id, and generic.py. From models.py
class TaggedItem(models.Model):
"""
Holds the relationship between a tag and the item being tagged.
"""
tag = models.ForeignKey(Tag, verbose_name=_('tag'), related_name='items')
content_type = models.ForeignKey(ContentType, verbose_name=_('content type'))
object_id = models.PositiveIntegerField(_('object id'), db_index=True)
object = generic.GenericForeignKey('content_type', 'object_id')
objects = TaggedItemManager()
class Meta:
# Enforce unique tag association per object
unique_together = (('tag', 'content_type', 'object_id'),)
verbose_name = _('tagged item')
verbose_name_plural = _('tagged items')
- How to build sphinx documentation for django project
- Django and Dropzone.js
- Make Django forms use comma as decimal separator
- Django Rest Framework 3.1 breaks pagination.PaginationSerializer
- Error installing mysqlclient for python on Ubuntu 18.04
1π
Anoher way to solve this is how django-mptt does this: define only an abstract model in a reusable app(MPTTModel), and require to inherit it with defining some fields (parent=ForeignKey to self, or whatever your app usecase will require)
- Django; AWS Elastic Beanstalk ERROR: Your WSGIPath refers to a file that does not exist
- Django: Tweaking @login_required decorator
- Django Multiple Databases Fallback to Master if Slave is down
0π
Probably you need to use the content types app to link to a model. You might then arrange for your app to check the settings to do some additional checking to limit which content types it will accept or suggest.
- In Django admin, how can I hide Save and Continue and Save and Add Another buttons on a model admin?
- Is there a command for creating an app using cookiecutter-django?
- Celery β No module named five
- How can I compare two fields of a model in a query?
- Python and sqlite3 β importing and exporting databases
0π
Iβd go with generic relations. You can do something like select_related, it just require some extra work. But I think itβs worth it.
One possible solution for generic select_related-like functionality:
http://bitbucket.org/kmike/django-generic-images/src/tip/generic_utils/managers.py
(look at GenericInjector manager and itβs inject_to method)
- Display query string values in django templates
- Django 3.1: StreamingHttpResponse with an async generator
0π
This question and Van Galeβs answer lead me to the question, how it could be possible, to limit contenttypes for GFK without the need of defining it via Q objects in the model, so it could be completly reuseable
the solution is based on
- django.db.models.get_model
- and the eval built-in, that evaluates a Q-Object from
settings.TAGGING_ALLOWED
. This is necessary for usage in the admin-interface
My code is quite rough and not fully tested
settings.py
TAGGING_ALLOWED=('myapp.modela', 'myapp.modelb')
models.py:
from django.db import models
from django.db.models import Q
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db.models import get_model
from django.conf import settings as s
from django.db import IntegrityError
TAGABLE = [get_model(i.split('.')[0],i.split('.')[1])
for i in s.TAGGING_ALLOWED if type(i) is type('')]
print TAGABLE
TAGABLE_Q = eval( '|'.join(
["Q(name='%s', app_label='%s')"%(
i.split('.')[1],i.split('.')[0]) for i in s.TAGGING_ALLOWED
]
))
class TaggedItem(models.Model):
content_type = models.ForeignKey(ContentType,
limit_choices_to = TAGABLE_Q)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
def save(self, force_insert=False, force_update=False):
if self.content_object and not type(
self.content_object) in TAGABLE:
raise IntegrityError(
'ContentType %s not allowed'%(
type(kwargs['instance'].content_object)))
super(TaggedItem,self).save(force_insert, force_update)
from django.db.models.signals import post_init
def post_init_action(sender, **kwargs):
if kwargs['instance'].content_object and not type(
kwargs['instance'].content_object) in TAGABLE:
raise IntegrityError(
'ContentType %s not allowed'%(
type(kwargs['instance'].content_object)))
post_init.connect(post_init_action, sender= TaggedItem)
Of course the limitations of the contenttype-framework affect this solution
# This will fail
>>> TaggedItem.objects.filter(content_object=a)
# This will also fail
>>> TaggedItem.objects.get(content_object=a)
- How do I tell Django to save my test database?
- How to assert django uses particular template in pytest
- How to create a Django superuser if it doesn't exist non-interactively?