def get_queryset(self): user = self.request.user token = self.request.auth requests = self.get_request_filter() qs = None if requests and self.action == 'list': # Never return on destructive action return self.get_foirequest_queryset(requests=requests) elif user.is_authenticated: if not token or token.is_valid(self.read_scopes): qs = (FoiRequestFollower.objects.filter( user=user).order_by('-timestamp')) if qs is None: qs = FoiRequestFollower.objects.none() if self.action == 'list': follower_count = (FoiRequest.objects.filter( id=OuterRef('request')).values('pk').annotate( count=Count('followers'))) qs = qs.annotate( follow_count=Subquery(follower_count.values('count')), # follows by query definition follows=Value(True, output_field=NullBooleanField()), # can_follow by query definition can_follow=Value(True, output_field=NullBooleanField())) return qs
def get_foirequest_queryset(self, requests=None): if self.action != 'list': raise Exception('Bad call to foirequest queryset') user = self.request.user token = self.request.auth qs = get_read_foirequest_queryset(self.request) if requests is not None: qs = qs.filter(id__in=requests) if user.is_authenticated and (not token or token.is_valid(self.read_scopes)): follows = (FoiRequestFollower.objects.filter( request_id=OuterRef('pk'), user=user)) qs = qs.annotate(follows=Exists(follows), resource_uri=Subquery(follows.values('pk')), can_follow=Case(When(user_id=user.id, then=Value(False)), default=Value(True), output_field=NullBooleanField())) else: qs = qs.annotate(follows=Value(None, output_field=NullBooleanField()), can_follow=Value(None, output_field=NullBooleanField())) qs = qs.annotate(follow_count=Count('followers'), ) return qs
class qDefect(Model): TimeSlot = ForeignKey( TimeSlot, blank=True, null=True, ) Airplane = ForeignKey( Airplane, blank=True, null=True, ) ProblemArea = CharField( max_length=6, blank=True, null=True, ) Defect = ForeignKey( CaseHeader, blank=True, null=True, ) Fixer = ForeignKey( User, blank=True, null=True, ) isPartAvailable = NullBooleanField( blank=True, null=True, ) isPartSupplied = NullBooleanField( blank=True, null=True, ) ServicingPort = CharField(max_length=100, blank=True, null=True) CHOICES_STATUS = ( ('SCHEDULED', 'SCHEDULED'), ('TRANSFERRED', 'TRANSFERRED'), ('EXTENDED', 'EXTENDED'), ) Status = CharField( max_length=100, blank=True, null=True, choices=CHOICES_STATUS, default='SCHEDULED', ) DeadlineTime = TimeField( blank=True, null=True, ) def __str__(self): return str(self.id)
class PersonalSatisfaction(Model): planned = ArrayField(base_field=CharField(max_length=1000)) done = ArrayField(base_field=CharField(max_length=1000)) not_done = ArrayField(base_field=CharField(max_length=1000)) future_plans = ArrayField(base_field=CharField(max_length=1000)) wanted_position = CharField(max_length=100) work_life_balance = PositiveIntegerField( validators=[MinValueValidator(1), MaxValueValidator(10)]) conference_wanted = NullBooleanField() helping_newcomers = NullBooleanField() date_created = DateField()
def test_boolean_constraints(self): """Boolean fields have check constraints on their values.""" for field in (BooleanField(), NullBooleanField(), BooleanField(null=True)): with self.subTest(field=field): field.set_attributes_from_name('is_nice') self.assertIn('"IS_NICE" IN (0,1)', field.db_check(connection))
class PollReplyLine(CremeModel, _PollLine): preply = ForeignKey(settings.POLLS_REPLY_MODEL, editable=False, related_name='lines', on_delete=CASCADE) section = ForeignKey(PollReplySection, editable=False, null=True, on_delete=CASCADE) # related_name='lines' pform_line = ForeignKey(PollFormLine, editable=False, on_delete=CASCADE) # related_name='lines' order = PositiveIntegerField(editable=False, default=1) type = PositiveSmallIntegerField(editable=False) type_args = TextField(editable=False, null=True) # null=True -> no conditions (NB: can we use it to avoid queries ?) applicable = BooleanField(_('Applicable'), default=True, editable=False) # null=True -> no conditions (NB: can we use it to avoid queries ?) conds_use_or = NullBooleanField(_('Use OR or AND between conditions'), editable=False) question = TextField(_('Question')) raw_answer = TextField(_('Answer'), null=True) # NULL == not answered [tip: use the property 'answer'] class Meta: app_label = 'polls' ordering = ('order',) def __repr__(self): from django.utils.encoding import smart_str return smart_str('PollReplyLine(section={}, question="{}", answer="{}")'.format( self.section_id, self.question, self.answer )) @classmethod def _get_condition_class(cls): # See _PollLine return PollReplyLineCondition @property def answer(self): try: return self.poll_line_type.decode_answer(self.raw_answer) except Exception: return 'INVALID' @answer.setter def answer(self, value): self.raw_answer = self.poll_line_type.encode_answer(value) @property def answer_formfield(self): line_type = self.poll_line_type if line_type.editable: answer_field = line_type.formfield(self.raw_answer) answer_field.label = gettext('Answer') else: answer_field = None return answer_field @property def stats(self): if not self.applicable: return [] return self.poll_line_type.get_stats(self.raw_answer)
class NamedCellMLEntity(DjangoModel): PRIVACY_LEVELS = [ ("Public", "Public"), ("Private", "Private"), # ("Selected ", "SU"), ] # These are the dynamic parts of a model which can be changed by the users name = CharField(blank=False, max_length=100) # The name of the entity # ready = NullBooleanField() # object in database has all fields completed TODO not working yet privacy = CharField(max_length=9, choices=PRIVACY_LEVELS, default="private", null=True, blank=True) notes = TextField(blank=True) owner = ForeignKey('Person', blank=True, null=True, on_delete=SET_NULL) # TODO set to admin annotations = ManyToManyField('Annotation', blank=True, related_name="used_by_%(class)s_objects") # CellML and libCellML fields: cellml_id = CharField(blank=True, max_length=100) # Mimics the cellml field 'id', not really needed here cellml_index = IntegerField(default=-1, null=True) # The corresponding item index as read by libCellML # Validation and error checking fields is_valid = NullBooleanField() last_checked = DateTimeField(blank=True, null=True) errors = ManyToManyField('ItemError', blank=True, related_name="error_in_%(class)s_objects") # This is the list of all downstream errors from this object, it's expensive to build so will update when asked error_tree = JSONField(blank=True, null=True) child_list = JSONField(blank=True, null=True) class Meta: abstract = True def __str__(self): return self.name
class AllAdvisersReport(QuerySetReport): """Admin report for all advisers.""" id = 'all-advisers' name = 'All advisers' model = Advisor permissions_required = ('company.view_advisor', ) queryset = Advisor.objects.annotate( name=get_full_name_expression(), is_team_active=Case( When(dit_team__disabled_on__isnull=True, dit_team__isnull=False, then=True), When(dit_team__disabled_on__isnull=False, then=False), default=None, output_field=NullBooleanField(), ), ).order_by( 'date_joined', 'pk', ) field_titles = { 'id': 'Adviser ID', 'email': 'Username', 'name': 'Name', 'contact_email': 'Contact email', 'is_active': 'Is active', 'dit_team__name': 'Team', 'is_team_active': 'Is team active', 'dit_team__role__name': 'Team role', }
class TestModelFields(Model): big_int = BigIntegerField() yesno = BooleanField() title = CharField(max_length=150) csv_data = CommaSeparatedIntegerField(max_length=255) when = DateField() when_accurate = DateTimeField() amount = DecimalField(max_digits=8, decimal_places=4) email = EmailField() upload = FileField(upload_to='test') path = FilePathField(path=d.APP_DIR, recursive=False, match=".json$") inaccurate = FloatField() img = ImageField(upload_to='test') ip = IPAddressField() better_ip = GenericIPAddressField(protocol='both') yesnomaybe = NullBooleanField(default=None) posint = PositiveIntegerField() small_posint = PositiveSmallIntegerField() slug = SlugField() small_int = SmallIntegerField() content = TextField() when_time = TimeField() web_address = URLField() user = ForeignKey('auth.User') groups = ManyToManyField('auth.Group') one_to_one = OneToOneField('auth.Permission') class Meta: verbose_name = 'test model fields' verbose_name_plural = 'test model fields'
def deprecate_field(field_instance, return_instead=None): """ Can be used in models to delete a Field in a Backwards compatible manner. The process for deleting old model Fields is: 1. Mark a field as deprecated by wrapping the field with this function 2. Wait until (1) is deployed to every relevant server/branch 3. Delete the field from the model. For (1) and (3) you need to run ./manage.py makemigrations: :param field_instance: The field to deprecate :param return_instead: A value or function that the field will pretend to have """ if not set(sys.argv) & {"makemigrations", "migrate"}: if not callable(return_instead): return return_instead return return_instead() if not type(field_instance) == BooleanField: field_instance.null = True return field_instance # A BooleanField does not allow null=True, so we need to cast # this to a NullBooleanField return NullBooleanField(help_text=field_instance.help_text, default=field_instance.default)
def get_queryset(self, request): qs = super().get_queryset(request) qs = qs.annotate(captured_amount=Sum('payments__captured_amount'), ) qs = qs.annotate(is_paid=Case(When( captured_amount__gte=F('total_gross'), then=Value(True)), default=Value(False), output_field=NullBooleanField())) return qs.select_related('subscription', 'user')
class BaseAttribute(Model): """ Base class for choices. Concrete choice class must overload the `schema` and `choice` attributes. """ entity_type = ForeignKey(ContentType) entity_id = IntegerField() entity = generic.GenericForeignKey(ct_field="entity_type", fk_field='entity_id') value_text = TextField(blank=True, null=True) value_float = FloatField(blank=True, null=True) value_date = DateField(blank=True, null=True) value_bool = NullBooleanField( blank=True) # TODO: ensure that form invalidates null booleans (??) #value_range_min = FloatField(blank=True, null=True) #value_range_max = FloatField(blank=True, null=True) #value_object = generic.GenericForeignKey(ct_field='generic_value_ct', fk_field='generic_value_id') schema = NotImplemented # must be FK choice = NotImplemented # must be nullable FK class Meta: abstract = True verbose_name, verbose_name_plural = _('attribute'), _('attributes') ordering = ['entity_type', 'entity_id', 'schema'] unique_together = ('entity_type', 'entity_id', 'schema', 'choice') def __unicode__(self): return u'%s: %s "%s"' % (self.entity, self.schema.title, self.value) def _get_value(self): if self.schema.datatype in (self.schema.TYPE_ONE, self.schema.TYPE_MANY): return self.choice '''if self.schema.datatype == self.schema.TYPE_RANGE: names = ('value_range_%s' % x for x in ('min', 'max')) value = tuple(getattr(self, x, None) for x in names) return None if value == (None, None) else value''' return getattr(self, 'value_%s' % self.schema.datatype) def _set_value(self, new_value): '''if self.schema.datatype == self.schema.TYPE_RANGE: new_value = new_value or (None, None) # validate range value -- expecting a tuple of two numbers try: validate_range_value(new_value) except (TypeError, ValueError): raise for k,v in zip('min max'.split(), new_value): v = v if v is None else float(v) setattr(self, 'value_range_%s' % k, v) else: setattr(self, 'value_%s' % self.schema.datatype, new_value)''' setattr(self, 'value_%s' % self.schema.datatype, new_value) value = property(_get_value, _set_value)
class event(Model): campaign = ForeignKey(campaign, null=True, on_delete=PROTECT) description = TextField(null=True) level = TextField() result = ForeignKey(result, null=True, on_delete=PROTECT) source = TextField() success = NullBooleanField() timestamp = DateTimeField(auto_now_add=True) type = TextField()
class Profile(models.Model): GENDER_CHOICES = ( ( 2, u'Мужской', ), ( 1, u'Женский', ), ( 0, u'Без указания пола', ), ) user = AutoOneToOneField(User, primary_key=True, related_name='vk_profile') nickname = CharField(u'nick', max_length=100, blank=True, null=True) domain = CharField(u'Адрес в url', max_length=50, blank=True, null=True) sex = IntegerField(u'Пол', blank=True, null=True, choices=GENDER_CHOICES) bdate = CharField(u'Дата рождения', max_length=10, blank=True, null=True) city = ForeignKey(City, blank=True, null=True) country = ForeignKey(Country, blank=True, null=True) timezone = IntegerField(u'Часовой пояс', blank=True, null=True) photo = URLField(blank=True, null=True) photo_medium = URLField(blank=True, null=True) photo_big = URLField(blank=True, null=True) photo_rec = URLField(blank=True, null=True) rate = IntegerField(u'Рейтинг', blank=True, null=True) has_mobile = NullBooleanField(u'Есть сотовый', blank=True, null=True) home_phone = CharField(u'Домашний телефон', max_length=30, blank=True, null=True) mobile_phone = CharField(u'Сотовый телефон', max_length=30, blank=True, null=True) university = IntegerField(u'Университет (id)', blank=True, null=True) university_name = CharField(u'Университет', max_length=50, blank=True, null=True) faculty = IntegerField(u'Факультет (id)', blank=True, null=True) faculty_name = CharField(u'Факультет', max_length=50, blank=True, null=True) graduation = CharField(u'Год выпуска', max_length=4, blank=True, null=True) class Meta: verbose_name = u'[vk] Данные о пользователе' verbose_name_plural = u'[vk] Данные о пользователях'
def test_boolean_value_annotation(self): books = Book.objects.annotate( is_book=Value(True, output_field=BooleanField()), is_pony=Value(False, output_field=BooleanField()), is_none=Value(None, output_field=NullBooleanField()), ) self.assertGreater(len(books), 0) for book in books: self.assertIs(book.is_book, True) self.assertIs(book.is_pony, False) self.assertIsNone(book.is_none)
class Gewas(Model): #1 Teeltgroepen, toepassingssectoren #101 Gewasgroepen, toepassingsgebieden #10101 Sub-gewasgroep #1010101 Gewas niveau = SmallIntegerField(choices=((1,'1. Teeltgroepen, toepassingssectoren'), (2, '2. Gewasgroepen, toepassingsgebieden'), (3, '3. Sub-gewasgroep'), (4, '4. Gewas')) ) edi_code = CharField(max_length=10) edi_naam = CharField(max_length=255) edi_periode = CharField(max_length=50, blank=True, null=True) #komma-gescheiden opties, TODO: n-m koppeling edi_teeltdoel = CharField(max_length=255, blank=True, null=True) #komma-gescheiden opties, TODO: n-m koppeling teelt_onbedekt = NullBooleanField() teelt_bedekt = NullBooleanField() teelt_opkweek_bedekt = NullBooleanField() dr_gewas_object = CharField(max_length=50) dr_opmerkingen_teeltdoel = CharField(max_length=255) dr_code = IntegerField(null=True) mest_gewas_object = CharField(max_length=50) mest_opmerkingen_teeltdoel = CharField(max_length=255) mest_code = CharField(max_length=50) def get_parent(self): if self.niveau <= 1: return None return Gewas.objects.filter(niveau=self.niveau-1, edi_code=self.edi_code[:-2]) def get_parent_code(self): if self.niveau <= 1: return None return self.edi_code[:-2] def __unicode__(self): return self.edi_naam class Meta: ordering = ['edi_naam','edi_code'] verbose_name_plural = "gewassen"
class TriggerResponse(AuthoredModel): trigger = CharField(max_length=200) response = TextField() source_state = CharField(max_length=200) dest_state = CharField(max_length=200) is_globstar = NullBooleanField(choices=CHOICES_IS_GLOBSTAR, max_length=3, null=True, blank=True, default=None) def __str__(self): return self.source_state + ' to ' + self.dest_state
class Proposition(Model): band = ForeignKey(Band, related_name='propositions') host = ForeignKey(Host, related_name='propositions') event = ForeignKey(Event, related_name='propositions') message = TextField(null=False) price = DecimalField(max_digits=6, decimal_places=2) confirmed = NullBooleanField(default=None) class Meta: unique_together = (('band', 'event'), ) def __str__(self): return '{}\'s to play at {}'.format(self.band.name, self.event.name)
class Question(Model): ref = ForeignKey('self', db_column='ref_id', blank=True, null=True, related_name='distortion', verbose_name='原题') charpter = ForeignKey(Charpter, db_column='charpter_id', related_name='questions', verbose_name='归属章节') content = TextField(verbose_name='题目内容') type = ForeignKey(CodeQuesthionType, db_column='type', related_name='questions', verbose_name='题目类型') owner = ForeignKey(Org, db_column='owner', related_name='own_questions', verbose_name='所有人') answer = TextField(blank=True, default='', verbose_name='回答') answer_type = ForeignKey(CodeContextType, db_column='answer_type', verbose_name='答题类型') difficultly = SmallIntegerField(default=1, verbose_name='难度') solve = TextField(blank=True, default='', verbose_name='解析') created_date = DateTimeField(auto_now_add=True) created_by = ForeignKey(User, db_column='created_by', related_name='created_questions', verbose_name='创建者') edit_by = ForeignKey(User, db_column='edit_by', related_name='edited_questions', null=True, blank=True, verbose_name='编辑者') status = SmallIntegerField(default=1, verbose_name='状态') share = NullBooleanField(null=True, default=False, verbose_name='是否可以分享') library = ForeignKey(Library, db_column='library_id', verbose_name='图书馆') comments = CharField(max_length=500, blank=True, verbose_name='备注') class Meta: app_label = 'question' db_table = 'questions' verbose_name = '题目' verbose_name_plural = '题目' def __unicode__(self): return u'{0}...'.format(self.content[:10])
def annotate_finished_by_date(self, date): from common.models import AdditionalAgreement from common.models import FinishedCinemaReportDate finished_cinemas_ids = FinishedCinemaReportDate.objects.filter( date=date).values_list('cinema_id', flat=True) active_agreements_ids = AdditionalAgreement.objects.filter_by_date( date).values_list('cinema', flat=True) return self.annotate( is_daily_report_finished=Case( When(id__in=finished_cinemas_ids, then=True), When(~Q(id__in=active_agreements_ids), then=None), default=Value(False), output_field=NullBooleanField()))
class ComplicatedTestModel(Model): char_field = CharField(max_length=32) bigint_field = BigIntegerField() boolean_field = BooleanField() commaseparatedinteger_field = CommaSeparatedIntegerField(max_length=32) date_field = DateField() datetime_field = DateTimeField() decimal_field = DecimalField(decimal_places=2, max_digits=20) email_field = EmailField() file_field = FileField() filepath_field = FilePathField(path="/home") float_field = FloatField() image_field = ImageField() integer_field = IntegerField() ipaddress_field = IPAddressField() nullboolean_field = NullBooleanField() positiveinteger_field = PositiveIntegerField() positivesmallinteger_field = PositiveSmallIntegerField() slug_field = SlugField() smallinteger_field = SmallIntegerField() text_field = TextField() url_field = URLField() def auto_populate(self): self.char_field = 'foo' self.bigint_field = 2379238742398 self.boolean_field = True self.commaseparatedinteger_field = '1, 2, 3, 4' self.date_field = datetime.datetime(2014, 1, 1) self.datetime_field = datetime.datetime(2014, 1, 1) self.decimal_field = 3.14 self.email_field = '*****@*****.**' self.file_field = 'test.txt' self.filepath_field = 'test.txt' self.float_field = 3.14 self.image_field = 'test.png' self.integer_field = 1024 self.ipaddress_field = '8.8.8.8' self.nullboolean_field = None self.positiveinteger_field = 1024 self.positivesmallinteger_field = 1024 self.slug_field = 'eat-slugs-all-day-long' self.smallinteger_field = 3 self.text_field = 'foo bar var\nvar bar foo' self.url_field = 'http://example.com'
class result(Model): aux_output = TextField(default=str) aux_serial_port = TextField(null=True) campaign = ForeignKey(campaign) returned = NullBooleanField() cycles = BigIntegerField(null=True) data_diff = FloatField(null=True) debugger_output = TextField(default=str) detected_errors = IntegerField(null=True) dut_output = TextField(default=str) dut_serial_port = TextField(null=True) execution_time = FloatField(null=True) num_injections = IntegerField(null=True) num_register_diffs = IntegerField(null=True) num_memory_diffs = IntegerField(null=True) outcome = TextField() outcome_category = TextField() timestamp = DateTimeField(auto_now_add=True)
class AssignmentPublish(Model): assignment = ForeignKey(Assignment, db_column='assignment_id', verbose_name='作业') publisher = ForeignKey(User, db_column='publisher', verbose_name='发布人') reciver_org = ForeignKey(Org, db_column='reciver_org', verbose_name='接收组织') share = NullBooleanField(default=False, verbose_name='是否分享') created_date = DateTimeField(auto_now_add=True, verbose_name='创建时间') publish_date = DateTimeField(auto_now_add=True, verbose_name='指定发布日期') submit_date_start = DateTimeField(auto_now_add=True, verbose_name='最早提交时间') submit_date_end = DateTimeField(verbose_name='最晚提交时间') comments = CharField(max_length=500, blank=True, verbose_name='备注') class Meta: app_label = 'question' db_table = 'assignment_publish' verbose_name = '作业发布情况' verbose_name_plural = '作业发布情况' def __unicode__(self): return u'{0}——{1}'.format(self.publisher.username, self.assignment.title)
class edge(models.Model): trigger = CharField(max_length=200, default='') response = CharField(max_length=200, default='') source = models.ForeignKey(node, on_delete=models.CASCADE, related_name='source', null=True) dest = models.ForeignKey(node, on_delete=models.CASCADE, related_name='dest', null=True) is_globstar = NullBooleanField(choices=CHOICES_IS_GLOBSTAR, max_length=3, null=True, blank=True, default=None) def __str__(self): return self.trigger + ' to ' + self.response
class Transaction(models.Model): account = ForeignKey(Account, on_delete=models.CASCADE) account_owner = CharField(max_length=50, null=True, blank=True) amount = FloatField() authorized_date = DateField(null=True, blank=True) category = JSONField(null=True, blank=True) date = DateField(null=True, blank=True) iso_currency_code = CharField(max_length=15, null=True, blank=True) location = JSONField(null=True, blank=True) merchant_name = CharField(max_length=50, null=True, blank=True) name = CharField(max_length=50, null=True, blank=True) payment_channel = CharField(max_length=50, null=True, blank=True) payment_meta = JSONField(null=True, blank=True) pending = NullBooleanField() pending_transaction_id = CharField(max_length=100, null=True, blank=True) transaction_code = CharField(max_length=100, null=True, blank=True) transaction_id = CharField(max_length=100, null=True, blank=True) transaction_type = CharField(max_length=25, null=True, blank=True) unofficial_currency_code = CharField(max_length=15, null=True, blank=True) is_deleted = BooleanField(default=False)
class result(Model): aux_output = TextField(default=str) aux_serial_port = TextField(null=True) campaign = ForeignKey(campaign, on_delete=PROTECT) returned = NullBooleanField() cycles = BigIntegerField(null=True) data_diff = FloatField(null=True) data_hash = TextField(null=True) debugger_output = TextField(default=str) detected_errors = IntegerField(null=True) dut_dev_serial = TextField(null=True) dut_output = TextField(default=str) dut_serial_port = TextField(null=True) execution_time = FloatField(null=True) num_injections = IntegerField(null=True) num_register_diffs = IntegerField(null=True) num_memory_diffs = IntegerField(null=True) outcome = TextField() outcome_category = TextField() previous_result = OneToOneField('self', null=True, related_name='next_result', on_delete=SET_NULL) timestamp = DateTimeField(auto_now_add=True)
class Publishable(Model): """ Base model for Article and Page models. """ preview_id = UUIDField(default=uuid.uuid4) revision_id = PositiveIntegerField(default=0, db_index=True) head = NullBooleanField(default=None, db_index=True, null=True) is_published = NullBooleanField(default=None, db_index=True) is_active = NullBooleanField(default=True) published_version = PositiveIntegerField(null=True) latest_version = PositiveIntegerField(null=True) slug = SlugField(max_length=255, db_index=True) shares = PositiveIntegerField(default=0, blank=True, null=True) views = PositiveIntegerField(default=0) featured_image = ForeignKey('ImageAttachment', on_delete=SET_NULL, related_name='%(class)s_featured_image', blank=True, null=True) featured_video = ForeignKey('VideoAttachment', on_delete=SET_NULL, related_name='%(class)s_featured_video', blank=True, null=True) template = CharField(max_length=255, default='default') template_data = JSONField(default={}) seo_keyword = CharField(max_length=100, null=True) seo_description = TextField(null=True) integrations = JSONField(default={}) content = JSONField(default=[]) snippet = TextField(null=True) created_at = DateTimeField() updated_at = DateTimeField() published_at = DateTimeField(null=True) objects = PublishableManager() @property def template_fields(self): if not hasattr(self, '_template_fields'): template = self.get_template() if template: template.set_data(self.template_data) self._template_fields = template.prepare_data() return self._template_fields def add_view(self): self.views += 1 self.save(revision=False) def get_template_path(self): if self.template != 'default': return 'article/%s.html' % self.template else: return 'article/default.html' def get_template(self): if not hasattr(self, '_template'): from dispatch.theme import ThemeManager try: self._template = ThemeManager.Templates.get(self.template) except: self._template = None return self._template @property def html(self): """Return HTML representation of content""" return content_to_html(self.content, self.id) def is_parent(self): return self.parent is None def publish(self): # Unpublish last published version type(self).objects.filter(parent=self.parent, is_published=True).update(is_published=None, published_at=None) self.is_published = True if self.published_at is None: self.published_at = timezone.now() self.save(revision=False) # Set published version for all articles type(self).objects.filter(parent=self.parent).update( published_version=self.revision_id) self.published_version = self.revision_id return self def unpublish(self): type(self).objects.filter(parent=self.parent, is_published=True).update(is_published=None, published_at=None) self.is_published = None # Unset published version for all articles type(self).objects.filter(parent=self.parent).update( published_version=None) self.published_version = None return self # Overriding @transaction.atomic def save(self, revision=True, *args, **kwargs): """ Handles the saving/updating of a Publishable instance. Arguments: revision - if True, a new version of this Publishable will be created. """ if revision: # If this is a revision, set it to be the head of the list and increment the revision id self.head = True self.revision_id += 1 previous_revision = self.get_previous_revision() if not self.is_parent(): # If this is a revision, delete the old head of the list. type(self).objects \ .filter(parent=self.parent, head=True) \ .update(head=None) # Clear the instance id to force Django to save a new instance. # Both fields (pk, id) required for this to work -- something to do with model inheritance self.pk = None self.id = None # New version is unpublished by default self.is_published = None # Set created_at to current time, but only for first version if not self.created_at: self.created_at = timezone.now() self.updated_at = timezone.now() if revision: self.updated_at = timezone.now() super(Publishable, self).save(*args, **kwargs) # Update the parent foreign key if not self.parent: self.parent = self super(Publishable, self).save(update_fields=['parent']) if revision: # Set latest version for all articles type(self).objects \ .filter(parent=self.parent) \ .update(latest_version=self.revision_id) self.latest_version = self.revision_id return self # Overriding delete the parent article to cascade delete all versions def delete(self, *args, **kwargs): if self.parent == self: return super(Publishable, self).delete(*args, **kwargs) return self.parent.delete() def save_featured_image(self, data): """ Handles saving the featured image. If data is None, the featured image will be removed. `data` should be dictionary with the following format: { 'image_id': int, 'caption': str, 'credit': str } """ attachment = self.featured_image if data is None: if attachment: attachment.delete() self.featured_image = None return if data['image_id'] is None: if attachment: attachment.delete() self.featured_image = None return if not attachment: attachment = ImageAttachment() attachment.image_id = data.get('image_id', attachment.image_id) attachment.caption = data.get('caption', None) attachment.credit = data.get('credit', None) instance_type = str(type(self)).lower() setattr(attachment, instance_type, self) attachment.save() self.featured_image = attachment def save_featured_video(self, data): attachment = self.featured_video if data is None: if attachment: attachment.delete() self.featured_video = None return if data['video_id'] is None: if attachment: attachment.delete() self.featured_video = None return if not attachment: attachment = VideoAttachment() attachment.video_id = data.get('video_id', attachment.video_id) attachment.caption = data.get('caption', None) attachment.credit = data.get('credit', None) instance_type = str(type(self)).lower() setattr(attachment, instance_type, self) attachment.save() self.featured_video = attachment def get_previous_revision(self): if self.parent == self: return self try: revision = type(self).objects \ .filter(parent=self.parent) \ .order_by('-pk')[1] return revision except: return self class Meta: abstract = True
class Domain(CleanSave, TimestampedModel): """A `Domain`. :ivar name: The DNS stuffix for this zone :ivar authoritative: MAAS manages this (forward) DNS zone. :ivar objects: An instance of the class :class:`DomainManager`. """ class Meta(DefaultMeta): """Needed for South to recognize this model.""" verbose_name = "Domain" verbose_name_plural = "Domains" objects = DomainManager() name = DomainNameField( max_length=256, editable=True, null=False, blank=False, unique=True, validators=[validate_domain_name], ) # We manage the forward zone. authoritative = NullBooleanField(default=True, db_index=True, editable=True) # Default TTL for this Domain. # If None and not overridden lower, then we will use the global default. ttl = PositiveIntegerField(default=None, null=True, blank=True) def update_kms_srv(self, kms_host=-1): # avoid recursive imports from maasserver.models import DNSData, DNSResource # Since None and '' are both valid values, we use -1 as the "I want the # default value" indicator, and fetch the Config value accordingly. if kms_host == -1: kms_host = Config.objects.get_config("windows_kms_host") if kms_host is None or kms_host == "": # No more Config.windows_kms_host, so we need to delete the kms # host entries that we may have created. The for loop is over 0 or # 1 DNSResource records for dnsrr in self.dnsresource_set.filter(name="_vlmcs._tcp"): dnsrr.dnsdata_set.filter( rrtype="SRV", rrdata__startswith="0 0 1688 ").delete() else: # force kms_host to be an FQDN (with trailing dot.) validate_domain_name(kms_host) if not kms_host.endswith("."): kms_host += "." # The windows_kms_host config parameter only manages priority 0, # weight 0, port 1688. To do something different, use the # dnsresources api. srv_data = "0 0 1688 %s" % kms_host dnsrr, _ = DNSResource.objects.get_or_create(domain_id=self.id, name="_vlmcs._tcp", defaults={}) srv, created = DNSData.objects.update_or_create( dnsresource_id=dnsrr.id, rrtype="SRV", rrdata__startswith="0 0 1688 ", defaults=dict(rrdata=srv_data), ) def get_base_ttl(self, rrtype, default_ttl): # If there is a Resource Record set, which has a non-None TTL, then it # wins. Otherwise our ttl if we have one, or the passed-in default. from maasserver.models import DNSData rrset = (DNSData.objects.filter( rrtype=rrtype, ttl__isnull=False).filter( Q(dnsresource__name="@") | Q(dnsresource__name="")).filter( dnsresource__domain_id=self.id)) if rrset.count() > 0: return rrset.first().ttl elif self.ttl is not None: return self.ttl else: return default_ttl @property def resource_count(self): """How many DNSResource names are attached to this domain.""" from maasserver.models.dnsresource import DNSResource return DNSResource.objects.filter(domain_id=self.id).count() @property def resource_record_count(self): """How many total Resource Records come from non-Nodes.""" count = 0 for resource in self.dnsresource_set.all(): count += len(resource.ip_addresses.all()) count += len(resource.dnsdata_set.all()) return count def add_delegations(self, mapping, ns_host_name, dns_ip_list, default_ttl): """Find any subdomains that need to be added to this domain, and add them. This function updates the mapping to add delegations and any needed glue records for any domains that are descendants of this one. These are not in the database, because they may be multi-lable (foo.bar.maas and maas are domains, but bar.maas isn't), and we don't want to allow multi-label elements in the model, due to the extreme complexity it introduces. """ # Recursive includes. from maasserver.models.dnsresource import separate_fqdn subdomains = Domain.objects.filter(name__endswith="." + self.name) possible = subdomains[:] # Anything with an intervening domain should not be delegated from # this domain. for middle in possible: subdomains = subdomains.exclude(name__endswith="." + middle.name) for subdomain in subdomains: nsttl = subdomain.get_base_ttl("NS", default_ttl) ttl = subdomain.get_base_ttl("A", default_ttl) # Strip off this domain name from the end of the resource name. name = subdomain.name[:-len(self.name) - 1] # If we are authoritative for the subdomain, then generate the NS # and any needed glue records. These will automatically be in the # child zone. if subdomain.authoritative: mapping[name].rrset.add((nsttl, "NS", ns_host_name)) if ns_host_name.endswith("." + self.name): # The ns_host_name lives in a subdomain of this subdomain, # and we are authoritative for that. We need to add glue # to this subdomain. ns_name = separate_fqdn(ns_host_name, "NS", self.name)[0] for addr in dns_ip_list: if IPAddress(addr).version == 4: mapping[ns_name].rrset.add((ttl, "A", addr)) else: mapping[ns_name].rrset.add((ttl, "AAAA", addr)) # Also return any NS RRset from the dnsdata for the '@' label in # that zone. Add glue records for NS hosts as needed. for lhs in subdomain.dnsresource_set.filter(name="@"): for data in lhs.dnsdata_set.filter(rrtype="NS"): mapping[name].rrset.add((ttl, data.rrtype, data.rrdata)) # Figure out if we need to add glue, and generate it if # needed. if data.rrdata == "@": # This glue is the responsibility of the admin. continue if not data.rrdata.endswith("."): # Non-qualified NSRR, append the domain. fqdn = "%s.%s." % (data.rrdata, subdomain.name) elif not data.rrdata.endswith("%s." % subdomain.name): continue else: # NSRR is an FQDN in or under subdomain. fqdn = data.rrdata # If we get here, then the NS host is in subdomain, or some # subdomain thereof, and is not '@' in the subdomain. # Strip the trailing dot, and split the FQDN. h_name, d_name = separate_fqdn(fqdn[:-1], "NS") # Make sure we look in the right domain for the addresses. if d_name == subdomain.name: nsrrset = subdomain.dnsresource_set.filter(name=h_name) else: nsdomain = Domain.objects.filter(name=d_name) if not nsdomain.exists(): continue else: nsdomain = nsdomain[0] nsrrset = nsdomain.dnsresource_set.filter(name=h_name) h_name = fqdn[:-len(subdomain.name) - 2] for nsrr in nsrrset: for addr in nsrr.get_addresses(): if IPAddress(addr).version == 4: mapping[h_name].rrset.add((ttl, "A", addr)) else: mapping[h_name].rrset.add((ttl, "AAAA", addr)) def __str__(self): return "name=%s" % self.get_name() def __unicode__(self): return "name=%s" % self.get_name() def is_default(self): """Returns True if this is the default domain, False otherwise.""" # Iterate over cached objects. (There should be just one, in fact.) for defaults in self.globaldefault_set.all(): if defaults.domain_id == self.id: return True return False def get_name(self): """Return the name of the domain.""" return self.name def delete(self): if self.is_default(): raise ValidationError( "This domain is the default domain, it cannot be deleted.") super().delete() def save(self, *args, **kwargs): created = self.id is None super().save(*args, **kwargs) if created: self.update_kms_srv() # If there is a DNSResource in our parent domain that matches this # domain name, the migrate the DNSResource to the new domain. parent = Domain.objects.filter(name=".".join(self.name.split(".")[1:])) if parent.exists(): me = parent[0].dnsresource_set.filter(name=self.name.split(".")[0]) for rr in me: rr.name = "@" rr.domain = self rr.save() def clean_name(self): # Automatically strip any trailing dot from the domain name. if self.name is not None and self.name.endswith("."): self.name = self.name[:-1] def clean(self, *args, **kwargs): super().clean(*args, **kwargs) self.clean_name() def render_json_for_related_rrdata(self, for_list=False, include_dnsdata=True, as_dict=False, user=None): """Render a representation of this domain's related non-IP data, suitable for converting to JSON. :return: data""" from maasserver.models import DNSData, StaticIPAddress if include_dnsdata is True: rr_mapping = DNSData.objects.get_hostname_dnsdata_mapping( self, raw_ttl=True) else: # Circular imports. from maasserver.models.dnsdata import HostnameRRsetMapping rr_mapping = defaultdict(HostnameRRsetMapping) # Smash the IP Addresses in the rrset mapping, so that the far end # only needs to worry about one thing. ip_mapping = StaticIPAddress.objects.get_hostname_ip_mapping( self, raw_ttl=True) for hostname, info in ip_mapping.items(): if (user is not None and not user.is_superuser and info.user_id is not None and info.user_id != user.id): continue entry = rr_mapping[hostname[:-len(self.name) - 1]] entry.dnsresource_id = info.dnsresource_id if info.system_id is not None: entry.system_id = info.system_id entry.node_type = info.node_type if info.user_id is not None: entry.user_id = info.user_id for ip in info.ips: record_type = "AAAA" if IPAddress(ip).version == 6 else "A" entry.rrset.add((info.ttl, record_type, ip, None)) if as_dict is True: result = OrderedDict() else: result = [] for hostname, info in rr_mapping.items(): data = [ { "name": hostname, "system_id": info.system_id, "node_type": info.node_type, "user_id": info.user_id, "dnsresource_id": info.dnsresource_id, "ttl": ttl, "rrtype": rrtype, "rrdata": rrdata, "dnsdata_id": dnsdata_id, } for ttl, rrtype, rrdata, dnsdata_id in info.rrset if (info.user_id is None or user is None or user.is_superuser or (info.user_id is not None and info.user_id == user.id)) ] if as_dict is True: existing = result.get(hostname, []) existing.extend(data) result[hostname] = existing else: result.extend(data) return result
def test_get_schematic_type(self): self.assertEqual(get_schematics_type(type(NullBooleanField())), NullBooleanType)
def test_get_type(self): self.assertEqual(get_type(NullBooleanField()), NullBooleanField)