# coding=utf-8 from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from rapid.rapidforms import RapidAlternativesField from django.db import models __author__ = 'marcos' """ Model fields specific for Rapid Django. """ class AlternativeData(GenericForeignKey): """ A generic relation that Rapid will display as an inline form or a group of data at the edit and view actions. Create like a Django GenericForeignKey, but use an AlternativeDataTables instead of a ForeignKey to ContentTypes. That is, a model becomes something like this: class MyModel(models.Model): alt_data_type = rapidfields.AlternativeDataTables((Model1, Model2)) alt_data_id = models.PositiveIntegerField() alt_data = rapidfields.AlternativeData('alt_data_type', 'alt_data_id', verbose_name='fill either a model1 or a model2 object') In forms, Rapid will display a select widget with the options "model1" and "model2", and show the appropriate form after selected. """ is_rapid_alternatives = True def __init__(self, *args, **kwargs): verbose_name = kwargs.get('verbose_name') if 'verbose_name' in kwargs: del(kwargs['verbose_name']) super(AlternativeData, self).__init__(*args, **kwargs) if verbose_name: self.verbose_name = verbose_name elif self.name: self.verbose_name = self.name.replace('_', ' ') def formfield(self, **kwargs): kwargs['form_class'] = RapidAlternativesField # noinspection PyUnresolvedReferences return super(GenericForeignKey, self).formfield(**kwargs) class AlternativeDataTables(models.ForeignKey): """ Use an AlternativeDataTables model field on AlternativeData representations, instead of a ForeignKey with ContentTypes. """ is_rapid_alternatives = True def __init__(self, alternatives=(), **kwargs): """ Receives the same named parameters of a ForeignKey, but instead of a target table, receives a list of the tables that may keep the alternative data. :param alternatives: List of the tables that hold the alternative data. :param kwargs: Arguments to the ForeignKey, without a relationship target. """ pks = [] try: pks = [ContentType.objects.get_for_model(a).pk for a in alternatives] except RuntimeError: # Querying ContentType within a content type is an issue at migrations pass kwargs['limit_choices_to'] = {'pk__in': pks} kwargs['to'] = ContentType super(AlternativeDataTables, self).__init__(**kwargs) self.alternatives = alternatives