class ZipCode(models.Model): code = models.CharField(max_length=5, unique=True) bounds = GeometryField(geography=True) center = PointField() def __str__(self): return self.code
class ApiarySiteOnApproval(models.Model): apiary_site = models.ForeignKey('ApiarySite', ) approval = models.ForeignKey('Approval', ) available = models.BooleanField(default=False) site_status = models.CharField(default=SITE_STATUS_CURRENT, max_length=20, db_index=True) # site_available = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) wkb_geometry = PointField(srid=4326, blank=True, null=True) # store approved coordinates site_category = models.ForeignKey( 'SiteCategory', null=True, blank=True, ) objects = GeoManager() def __str__(self): return 'id:{}: (apiary_site: {}, approval: {})'.format( self.id, self.apiary_site.id, self.approval.id) class Meta: app_label = 'disturbance' unique_together = [ 'apiary_site', 'approval', ]
class Station(models.Model): code = models.CharField(max_length=4, unique=True) name = models.CharField(max_length=200) state = models.CharField(max_length=2) point = PointField() xml_url = models.CharField(max_length=200) last_fetched = models.DateTimeField(null=True, blank=True) def __str__(self): return self.name def fetch(self): r = requests.get(self.xml_url, timeout=5) doc = drill.parse(r.text) self.last_fetched = timezone.now() self.save(update_fields=('last_fetched', )) return self.weather.create(data=doc.json(), date_fetched=self.last_fetched) def latest(self): if self.last_fetched and (timezone.now() - self.last_fetched ) < datetime.timedelta(minutes=15): return self.weather.latest('date_fetched') else: return self.fetch()
class Occurrence(models.Model): geom = PointField() version = models.IntegerField(default=0) released_versions = models.IntegerField(default=0) occurrence_cat = models.ForeignKey(OccurrenceCategory, on_delete=models.SET_NULL, blank=True, null=True) released = models.BooleanField(default=False) verified = models.BooleanField(default=False) inclusion_date = models.DateTimeField(default=timezone.now) observation = models.OneToOneField(OccurrenceObservation, on_delete=models.CASCADE) class Meta: abstract = True
class Location(QuicksellModel): """Object's physical location.""" coordinates = PointField(unique=True) address = TextField(max_length=1024) @classmethod def default_pk(cls): return cls.objects.get_or_create(coordinates=Point(x=55.751426, y=37.618879), address="The Kremlin")[0].id
class Presence(CommonUserdata): class Meta: verbose_name = 'Гео-данные' verbose_name_plural = 'Гео-данные' def __str__(self): return u'{0} --- {1} {2}'.format( self.time_start.strftime('%Y-%m-%d %H:%M %Z'), self.time_end.strftime('%Y-%m-%d %H:%M %Z'), self.point.coords) point = PointField('Гео-точка')
class Place(models.Model): name = models.CharField(max_length=200) state = models.CharField(max_length=2) point = PointField() zipcode = models.ForeignKey(ZipCode, related_name='places', null=True, blank=True, on_delete=models.SET_NULL) def __str__(self): return self.name
class Station(models.Model): id = models.IntegerField(editable=False) location_label = models.CharField(editable=False) station_code = models.CharField(editable=False) station_label = models.CharField(editable=False) code = models.CharField(editable=False) parameter_id = models.IntegerField(editable=False) geo = PointField(editable=False, srid=4326) class Meta: managed = False db_table = 'measurements_station_geo'
class Migration(migrations.Migration): dependencies = [("aira", "0021_lint")] operations = [ migrations.AddField(model_name="agrifield", name="location", field=PointField(null=True)), migrations.AlterField(model_name="agrifield", name="latitude", field=FloatField(null=True)), migrations.AlterField(model_name="agrifield", name="longitude", field=FloatField(null=True)), migrations.RunPython(latlon2point, point2latlon), migrations.RemoveField(model_name="agrifield", name="latitude"), migrations.RemoveField(model_name="agrifield", name="longitude"), migrations.AlterField(model_name="agrifield", name="location", field=PointField(null=False)), ]
class LocativeModel(TimeStampedModel): point = PointField() altitude = models.FloatField(blank=True, null=True) accuracy = models.FloatField(blank=True, null=True) altitude_accuracy = models.FloatField(blank=True, null=True) objects = GeoManager() class Meta(TimeStampedModel.Meta): abstract = True def latlon(): #@NoSelf doc = """Returns the latitude/longitude pair as a dict for the API, etc.""" #@UnusedVariable def fget(self): #return self.point.geojson return {'lat': self.point.y, 'lon': self.point.x} return locals() latlon = property(**latlon())
class Salon(models.Model): name = models.CharField(max_length=255, null=True) timezone = TimeZoneField(default=settings.TIME_ZONE) address = models.CharField(max_length=255) city = models.CharField(max_length=64, null=True, blank=True) state = models.CharField(max_length=25, null=True, blank=True) country = models.CharField(max_length=25, null=True, blank=True) zip_code = models.CharField(max_length=16, null=True, blank=True) location = PointField(geography=True, null=True, blank=True) is_address_geocoded = models.BooleanField(default=False) public_phone = models.CharField(max_length=20, blank=True, null=True, default=None) last_geo_coded = models.DateTimeField(blank=True, null=True, default=None) class Meta: db_table = 'salon' def __str__(self) -> str: if self.name is not None: return '{0} ({1})'.format(self.name, self.get_full_address()) return '[No name] ({0})'.format(self.get_full_address()) def get_full_address(self) -> str: # TODO: change this to proper address generation return self.address def geo_code_address(self): geo_coded_address = GeocodeValidAddress(self.address).geo_code() if geo_coded_address: self.city = geo_coded_address.city self.state = geo_coded_address.state self.zip_code = geo_coded_address.zip_code self.location = geo_coded_address.location self.country = geo_coded_address.country self.is_address_geocoded = True logger.info('Geo-coding Success', exc_info=True) else: logger.info("Geo-coding returned None") self.last_geo_coded = timezone.now() self.save(update_fields=['city', 'state', 'zip_code', 'location', 'country', 'is_address_geocoded', 'last_geo_coded'])
class Place(models.Model): objects = PlaceManager() title = models.TextField() latlng = PointField() start_date = models.OneToOneField(ExtendedDate, null=True, blank=True, on_delete=models.SET_NULL, related_name='place_start_date') is_ended = models.BooleanField( default=True, help_text="Is the site or archive still at this location?") end_date = models.OneToOneField(ExtendedDate, null=True, blank=True, on_delete=models.SET_NULL, related_name='place_end_date') created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) def __str__(self): return self.title def latitude(self): return self.latlng.coords[1] def longitude(self): return self.latlng.coords[0] def match_string(self, latlng): s = '{},{}'.format(self.latitude(), self.longitude()) return s == latlng def get_absolute_url(self): return reverse('place-detail-view', kwargs={'pk': self.id})
class Migration(migrations.Migration): dependencies = [ ('parkings', '0024_permitlookupitem_index'), ] operations = [ migrations.CreateModel( name='ParkingCheck', fields=[ ('id', models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField( auto_now_add=True, db_index=True, verbose_name='time created')), ('time', models.DateTimeField(verbose_name='time')), ('time_overridden', models.BooleanField( verbose_name='time was overridden')), ('registration_number', models.CharField( max_length=20, verbose_name='registration number')), ('location', PointField( srid=4326, verbose_name='location')), ('result', JSONField( blank=True, encoder=DjangoJSONEncoder, verbose_name='result')), ('allowed', models.BooleanField( verbose_name='parking was allowed')), ('found_parking', models.ForeignKey( to='parkings.Parking', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='found parking')), ], options={ 'ordering': ('-created_at', '-id'), 'verbose_name': 'parking check', 'verbose_name_plural': 'parking checks' }, ), ]
class Location(models.Model): event = models.OneToOneField( Event, on_delete=models.CASCADE, ) # NOTE: Coorindates are stored as (lng, lat) # This is done to match DeckGL's convention point = PointField(blank=True, null=True) polygon = PolygonField(blank=True, null=True) @property def lng_lat(self): return [self.point.coords[0], self.point.coords[1] ] if self.point else None class Meta: constraints = [ models.CheckConstraint( name="value_either_point_or_polygon", check=(models.Q(point__isnull=False, polygon__isnull=True) | models.Q(point__isnull=True, polygon__isnull=False))) ]
class Institution(models.Model): objects = InstitutionManager() external_id = models.PositiveIntegerField(unique=True) title = models.TextField(unique=True) latlng = PointField() address = models.TextField(null=True, blank=True) city = models.TextField() state = models.CharField(max_length=2) website_url = models.URLField() image = models.URLField(null=True, blank=True) admissions_url = models.URLField(null=True, blank=True) private = models.BooleanField() student_population = models.PositiveIntegerField() undergraduate_population = models.PositiveIntegerField() undergrad_vet_population = models.PositiveIntegerField(null=True) undergrad_vet_graduation_rate = models.PositiveIntegerField(null=True) grad_vet_population = models.PositiveIntegerField(null=True) grad_vet_graduation_rate = models.PositiveIntegerField(null=True) two_year_program = models.BooleanField(null=True) four_year_program = models.BooleanField(null=True) accredited = models.BooleanField() accreditation_type = models.CharField( null=True, max_length=1, choices=ACCREDITATION_CHOICES) regional_accreditor = models.TextField(null=True, blank=True) standardized_test_required = models.BooleanField() standardized_test_notes = models.TextField(null=True, blank=True) vet_center = models.BooleanField() sva_chapter = models.BooleanField() clep_credits_accepted = models.BooleanField() jst_credits_accepted = models.BooleanField(null=True, blank=True) dsst_credits_accepted = models.BooleanField() online_credits_accepted = models.BooleanField() application_fee_waived = models.BooleanField() vet_grants_scholarships = models.BooleanField() vet_grants_scholarships_notes = models.TextField(null=True, blank=True) yellow_ribbon = models.BooleanField() yellow_ribbon_slots = models.TextField(null=True, blank=True) yellow_ribbon_contribution = models.TextField(null=True, blank=True) notes = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['title'] def __str__(self): return self.title def set_accreditation_type(self, value): self.accreditation_type = None value = value.lower() for s in ACCREDITATION_CHOICES: if value == s[1]: self.accreditation_type = s[0] def get_institution_type(self): return 'Private' if self.private else 'Public' def set_institution_type(self, value): self.private = 'private' in value.lower() def set_program_duration(self, value): value = value.lower() self.two_year_program = '2 year' in value self.four_year_program = '4 year' in value def set_latitude(self, value): if not self.latlng: self.latlng = Point(float(value), 0) else: self.latlng = Point(float(value), self.latlng.coords[1]) def set_longitude(self, value): if not self.latlng: self.latlng = Point(0, float(value)) else: self.latlng = Point(self.latlng.coords[0], float(value))
class Instance(models.Model): """A series of answers by an individual for a specific form""" UPLOADED_TO = "instances/" STATUS_READY = "READY" STATUS_DUPLICATED = "DUPLICATED" STATUS_EXPORTED = "EXPORTED" created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) uuid = models.TextField(null=True, blank=True) export_id = models.TextField(null=True, blank=True, default=generate_id_for_dhis_2) correlation_id = models.BigIntegerField(null=True, blank=True) name = models.TextField(null=True, blank=True) file = models.FileField(upload_to=UPLOADED_TO, null=True, blank=True) file_name = models.TextField(null=True, blank=True) location = PointField(null=True, blank=True, dim=3, srid=4326) org_unit = models.ForeignKey("OrgUnit", on_delete=models.DO_NOTHING, null=True, blank=True) form = models.ForeignKey("Form", on_delete=models.PROTECT, null=True, blank=True, related_name="instances") project = models.ForeignKey("Project", blank=True, null=True, on_delete=models.DO_NOTHING) json = JSONField(null=True, blank=True) accuracy = models.DecimalField(null=True, decimal_places=2, max_digits=7) device = models.ForeignKey("Device", null=True, blank=True, on_delete=models.DO_NOTHING) period = models.TextField(null=True, blank=True, db_index=True) last_export_success_at = models.DateTimeField(null=True, blank=True) objects = InstanceQuerySet.as_manager() deleted = models.BooleanField(default=False) def convert_location_from_field(self, field_name=None): f = field_name if f is None: f = self.form.location_field if self.json and f: location = self.json.get(f, None) if location: latitude, longitude, altitude, accuracy = [ float(x) for x in location.split(" ") ] self.location = Point(x=longitude, y=latitude, z=altitude, srid=4326) self.accuracy = accuracy self.save() def convert_device(self): if self.json and not self.device: device_field = self.form.device_field if not device_field: device_field = "deviceid" imei = self.json.get(device_field, None) if imei is not None: device, created = Device.objects.get_or_create(imei=imei) self.device = device self.save() if self.project: self.device.projects.add(self.project) def convert_correlation(self): if not self.correlation_id: identifier = str(self.id) if self.form.correlation_field is not None and self.json: identifier += self.json.get(self.form.correlation_field, None) identifier = identifier.zfill(3) random_number = random.choice("1234567890") value = int(identifier + random_number) suffix = "{:02d}".format(value % 97) self.correlation_id = identifier + random_number + suffix self.save() def get_and_save_json_of_xml(self): if self.json: file_content = self.json elif self.file: if "amazonaws" in self.file.url: file = urlopen(self.file.url) else: file = self.file soup = as_soup(file) form_version_id = extract_form_version_id(soup) if form_version_id: form_versions = self.form.form_versions.filter( version_id=form_version_id) form_version = form_versions.first() if form_version: self.json = flat_parse_xml_soup( soup, [rg["name"] for rg in form_version.repeat_groups()]) else: # warn old form, but keep it working ? or throw error self.json = flat_parse_xml_soup(soup, []) else: self.json = flat_parse_xml_soup(soup, []) file_content = self.json self.save() else: file_content = {} return file_content def get_form_version(self): json = self.get_and_save_json_of_xml() try: return self.form.form_versions.get(version_id=json["_version"]) except (KeyError, FormVersion.DoesNotExist): return None def export(self, launcher=None): from iaso.dhis2.datavalue_exporter import DataValueExporter from iaso.dhis2.export_request_builder import ExportRequestBuilder, NothingToExportError try: export_request = ExportRequestBuilder().build_export_request( filters={"instance_id": self.id}, launcher=None) DataValueExporter().export_instances(export_request, True) except NothingToExportError as error: print("Export failed for instance", self) def __str__(self): return "%s %s" % (self.form, self.name) def as_dict(self): file_content = self.get_and_save_json_of_xml() return { "uuid": self.uuid, "export_id": self.export_id, "file_name": self.file_name, "file_content": file_content, "file_url": self.file.url if self.file else None, "id": self.id, "form_id": self.form_id, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "org_unit": self.org_unit.as_dict( with_groups=False) if self.org_unit else None, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "period": self.period, "status": getattr(self, "status", None), "correlation_id": self.correlation_id, } def as_dict_with_parents(self): file_content = self.get_and_save_json_of_xml() return { "uuid": self.uuid, "export_id": self.export_id, "file_name": self.file_name, "file_content": file_content, "file_url": self.file.url if self.file else None, "id": self.id, "form_id": self.form_id, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "org_unit": self.org_unit.as_dict_with_parents() if self.org_unit else None, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "period": self.period, "status": getattr(self, "status", None), "correlation_id": self.correlation_id, } def as_full_model(self): file_content = self.get_and_save_json_of_xml() form_version = self.get_form_version() return { "uuid": self.uuid, "id": self.id, "device_id": self.device.imei if self.device else None, "file_name": self.file_name, "file_url": self.file.url if self.file else None, "form_id": self.form_id, "form_name": self.form.name, "form_descriptor": form_version.get_or_save_form_descriptor() if form_version is not None else None, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "org_unit": self.org_unit.as_dict_with_parents( light=False, light_parents=False) if self.org_unit else None, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "period": self.period, "file_content": file_content, "files": [ f.file.url if f.file else None for f in self.instancefile_set.all() ], "status": getattr(self, "status", None), "correlation_id": self.correlation_id, "last_export_success_at": self.last_export_success_at.timestamp() if self.last_export_success_at else None, "export_statuses": [{ "status": export_status.status, "created_at": export_status.created_at.timestamp() if export_status.created_at else None, "export_request": { "launcher": { "full_name": export_status.export_request.launcher.get_full_name() if export_status.export_request.launcher else "AUTO UPLOAD", "email": export_status.export_request.launcher.email if export_status.export_request.launcher else "AUTO UPLOAD", }, "last_error_message": f"{export_status.last_error_message}, {export_status.export_request.last_error_message}", }, } for export_status in Paginator( self.exportstatus_set.order_by("-id"), 3).object_list], "deleted": self.deleted, } def as_small_dict(self): return { "id": self.id, "file_url": self.file.url if self.file else None, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "period": self.period, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "files": [ f.file.url if f.file else None for f in self.instancefile_set.all() ], "status": getattr(self, "status", None), "correlation_id": self.correlation_id, } def soft_delete(self, user: typing.Optional[User] = None): with transaction.atomic(): original = copy(self) self.deleted = True self.save() log_modification(original, self, INSTANCE_API, user=user)
class Migration(migrations.Migration): initial = True dependencies = [("people", "0001_initial")] operations = [ migrations.CreateModel( name="Calendar", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "nb_id", models.IntegerField( blank=True, help_text= "L'identifiant de la ressource correspondante sur NationBuilder, si importé.", null=True, unique=True, verbose_name="ID sur NationBuilder", ), ), ( "label", models.CharField(max_length=50, unique=True, verbose_name="nom"), ), ( "description", models.TextField(blank=True, verbose_name="description"), ), ], options={"verbose_name": "agenda"}, ), migrations.CreateModel( name="Event", fields=[ ( "created", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="created", ), ), ( "modified", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="modified", ), ), ( "id", models.UUIDField( default=uuid.uuid4, help_text= "UUID interne à l'API pour identifier la ressource", primary_key=True, serialize=False, verbose_name="UUID", ), ), ( "nb_id", models.IntegerField( blank=True, help_text= "L'identifiant de la ressource correspondante sur NationBuilder, si importé.", null=True, unique=True, verbose_name="ID sur NationBuilder", ), ), ( "coordinates", PointField( blank=True, geography=True, null=True, srid=4326, verbose_name="coordonnées", ), ), ( "location_name", models.CharField(blank=True, max_length=255, verbose_name="nom du lieu"), ), ( "location_address", models.CharField(blank=True, max_length=255, verbose_name="adresse complète"), ), ( "location_address1", models.CharField(blank=True, max_length=100, verbose_name="adresse (1ère ligne)"), ), ( "location_address2", models.CharField(blank=True, max_length=100, verbose_name="adresse (2ème ligne)"), ), ( "location_city", models.CharField(blank=True, max_length=100, verbose_name="ville"), ), ( "location_zip", models.CharField(blank=True, max_length=20, verbose_name="code postal"), ), ( "location_state", models.CharField(blank=True, max_length=40, verbose_name="état"), ), ( "location_country", django_countries.fields.CountryField(blank=True, max_length=2, verbose_name="pays"), ), ( "contact_name", models.CharField(blank=True, max_length=255, verbose_name="nom du contact"), ), ( "contact_email", models.EmailField( blank=True, max_length=254, verbose_name="adresse email du contact", ), ), ( "contact_phone", models.CharField( blank=True, max_length=30, verbose_name="numéro de téléphone du contact", ), ), ( "name", models.CharField( help_text="Le nom du groupe de l'événement", max_length=255, verbose_name="nom", ), ), ( "description", models.TextField( blank=True, help_text="Une description de l'événement, en MarkDown", verbose_name="description", ), ), ( "nb_path", models.CharField(blank=True, max_length=255, verbose_name="NationBuilder path"), ), ( "start_time", models.DateTimeField( verbose_name="date et heure de début"), ), ("end_time", models.DateTimeField(verbose_name="date et heure de fin")), ], options={ "verbose_name": "événement", "verbose_name_plural": "événements", "ordering": ("-start_time", "-end_time"), "permissions": (("every_event", "Peut éditer tous les événements"), ), }, ), migrations.CreateModel( name="EventTag", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "label", models.CharField(max_length=50, unique=True, verbose_name="nom"), ), ( "description", models.TextField(blank=True, verbose_name="description"), ), ], options={"verbose_name": "tag"}, ), migrations.CreateModel( name="RSVP", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "created", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="created", ), ), ( "modified", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="modified", ), ), ( "guests", models.PositiveIntegerField( default=0, verbose_name="nombre d'invités supplémentaires"), ), ("canceled", models.BooleanField(default=False, verbose_name="Annulé")), ( "event", models.ForeignKey( editable=False, on_delete=django.db.models.deletion.CASCADE, related_name="rsvps", to="events.Event", ), ), ( "person", models.ForeignKey( editable=False, on_delete=django.db.models.deletion.CASCADE, related_name="rsvps", to="people.Person", ), ), ], options={ "verbose_name": "RSVP", "verbose_name_plural": "RSVP" }, ), migrations.AddField( model_name="event", name="attendees", field=models.ManyToManyField(related_name="events", through="events.RSVP", to="people.Person"), ), migrations.AddField( model_name="event", name="calendar", field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="events", to="events.Calendar", ), ), migrations.AddField( model_name="event", name="organizers", field=models.ManyToManyField(related_name="organized_events", to="people.Person"), ), migrations.AddField( model_name="event", name="tags", field=models.ManyToManyField(blank=True, related_name="events", to="events.EventTag"), ), migrations.AlterUniqueTogether(name="rsvp", unique_together={("event", "person")}), migrations.AddIndex( model_name="event", index=models.Index(fields=["start_time", "end_time"], name="events_even_start_t_0e446b_idx"), ), migrations.AddIndex( model_name="event", index=models.Index(fields=["nb_path"], name="events_even_nb_path_2e6795_idx"), ), ]
class ArchivalCollectionSuggestion(models.Model): person = models.TextField(verbose_name="Your Name") person_title = models.TextField(verbose_name="Your Title") email = models.EmailField(verbose_name="Your Email Address") repository_title = models.TextField() collection_title = models.TextField() latlng = PointField() title = models.TextField(verbose_name="Address") description = models.TextField(null=True, blank=True) finding_aid_url = models.URLField(null=True, blank=True) linear_feet = models.FloatField(null=True, blank=True) record_format = models.ManyToManyField(ArchivalRecordFormat, blank=True) inclusive_start = models.OneToOneField(ExtendedDate, null=True, blank=True, on_delete=models.SET_NULL, related_name='suggestion_start') inclusive_end = models.OneToOneField(ExtendedDate, null=True, blank=True, on_delete=models.SET_NULL, related_name='suggestion_end') archival_collection = models.ForeignKey(ArchivalCollection, null=True, blank=True, on_delete=models.SET_NULL) created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['repository_title', 'collection_title'] def get_or_create_repository(self): try: repo = ArchivalRepository.objects.get(title=self.repository_title) except ArchivalRepository.DoesNotExist: (place, created) = Place.objects.get_or_create(title=self.title, latlng=self.latlng, start_date=None, end_date=None) repo = ArchivalRepository.objects.create( place=place, title=self.repository_title) return repo def get_or_create_collection(self, repo): try: collection = ArchivalCollection.objects.get( collection_title=self.collection_title, repository=repo) except ArchivalCollection.DoesNotExist: collection = ArchivalCollection.objects.create( repository=repo, collection_title=self.collection_title, description=self.description, finding_aid_url=self.finding_aid_url, linear_feet=self.linear_feet, inclusive_start=self.inclusive_start, inclusive_end=self.inclusive_end) return collection def add_notes(self, collection): notes = 'Suggested by {}, {}'.format(self.person, self.person_title) if collection.notes: collection.notes = collection.notes + ' ' + notes else: collection.notes = notes collection.save() def convert_to_archival_collection(self): if self.archival_collection is not None: return self.archival_collection repo = self.get_or_create_repository() collection = self.get_or_create_collection(repo) self.add_notes(collection) self.archival_collection = collection self.save() return collection
class OrgUnit(models.Model): VALIDATION_NEW = "NEW" VALIDATION_VALID = "VALID" VALIDATION_REJECTED = "REJECTED" VALIDATION_STATUS_CHOICES = ( (VALIDATION_NEW, _("new")), (VALIDATION_VALID, _("valid")), (VALIDATION_REJECTED, _("rejected")), ) name = models.CharField(max_length=255) uuid = models.TextField(null=True, blank=True, db_index=True) custom = models.BooleanField(default=False) validated = models.BooleanField( default=True, db_index=True) # TO DO : remove in a later migration validation_status = models.CharField(max_length=25, choices=VALIDATION_STATUS_CHOICES, default=VALIDATION_NEW) version = models.ForeignKey("SourceVersion", null=True, blank=True, on_delete=models.CASCADE) parent = models.ForeignKey("OrgUnit", on_delete=models.CASCADE, null=True, blank=True) path = PathField(null=True, blank=True, unique=True) aliases = ArrayField(CITextField(max_length=255, blank=True), size=100, null=True, blank=True) org_unit_type = models.ForeignKey(OrgUnitType, on_delete=models.CASCADE, null=True, blank=True) sub_source = models.TextField( null=True, blank=True) # sometimes, in a given source, there are sub sources source_ref = models.TextField(null=True, blank=True, db_index=True) geom = MultiPolygonField(null=True, blank=True, srid=4326, geography=True) simplified_geom = MultiPolygonField(null=True, blank=True, srid=4326, geography=True) catchment = MultiPolygonField(null=True, blank=True, srid=4326, geography=True) geom_ref = models.IntegerField(null=True, blank=True) gps_source = models.TextField(null=True, blank=True) location = PointField(null=True, blank=True, geography=True, dim=3, srid=4326) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) creator = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) objects = OrgUnitManager.from_queryset(OrgUnitQuerySet)() class Meta: indexes = [GistIndex(fields=["path"], buffering=True)] def save(self, *args, skip_calculate_path: bool = False, **kwargs): """Override default save() to make sure that the path property is calculated and saved, for this org unit and its children. :param skip_calculate_path: use with caution - can be useful in scripts where the extra transactions would be a burden, but the path needs to be set afterwards """ if skip_calculate_path: super().save(*args, **kwargs) else: with transaction.atomic(): super().save(*args, **kwargs) OrgUnit.objects.bulk_update(self.calculate_paths(), ["path"]) def calculate_paths(self, force_recalculate: bool = False ) -> typing.List["OrgUnit"]: """Calculate the path for this org unit and all its children. This method will check if this org unit path should change. If it is the case (or if force_recalculate is True), it will update the path property for the org unit and its children, and return all the modified records. Please note that this method does not save the modified records. Instead, they are updated in bulk in the save() method. :param force_recalculate: calculate path for all descendants, even if this org unit path does not change """ # For now, we will skip org units that have a parent without a path. # The idea is that a management command (set_org_unit_path) will handle the initial seeding of the # path field, starting at the top of the pyramid. Once this script has been run and the field is filled for # all org units, this should not happen anymore. # TODO: remove condition below if self.parent is not None and self.parent.path is None: return [] # keep track of updated records updated_records = [] base_path = [] if self.parent is None else list(self.parent.path) new_path = [*base_path, str(self.pk)] path_has_changed = new_path != self.path if path_has_changed: self.path = new_path updated_records += [self] if path_has_changed or force_recalculate: for child in self.orgunit_set.all(): updated_records += child.calculate_paths(force_recalculate) return updated_records def __str__(self): return "%s %s %d" % (self.org_unit_type, self.name, self.id if self.id else -1) def as_dict_for_mobile_lite(self): return { "n": self.name, "id": self.id, "p": self.parent_id, "out": self.org_unit_type_id, "c_a": self.created_at.timestamp() if self.created_at else None, "lat": self.location.y if self.location else None, "lon": self.location.x if self.location else None, "alt": self.location.z if self.location else None, } def as_dict_for_mobile(self): return { "name": self.name, "id": self.id, "parent_id": self.parent_id, "org_unit_type_id": self.org_unit_type_id, "org_unit_type_name": self.org_unit_type.name if self.org_unit_type else None, "validation_status": self.validation_status if self.org_unit_type else None, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, } def as_dict(self, with_groups=True): res = { "name": self.name, "short_name": self.name, "id": self.id, "source": self.version.data_source.name if self.version else None, "source_ref": self.source_ref, "parent_id": self.parent_id, "org_unit_type_id": self.org_unit_type_id, "org_unit_type_name": self.org_unit_type.name if self.org_unit_type else None, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "aliases": self.aliases, "validation_status": self.validation_status, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "has_geo_json": True if self.simplified_geom else False, "version": self.version.number if self.version else None, } if hasattr(self, "search_index"): res["search_index"] = self.search_index return res def as_dict_with_parents(self, light=False, light_parents=True): res = { "name": self.name, "short_name": self.name, "id": self.id, "sub_source": self.sub_source, "sub_source_id": self.sub_source, "source_ref": self.source_ref, "source_url": self.version.data_source.credentials.url if self.version and self.version.data_source and self.version.data_source.credentials else None, "parent_id": self.parent_id, "validation_status": self.validation_status, "parent_name": self.parent.name if self.parent else None, "parent": self.parent.as_dict_with_parents(light=light_parents, light_parents=light_parents) if self.parent else None, "org_unit_type_id": self.org_unit_type_id, "created_at": self.created_at.timestamp() if self.created_at else None, "updated_at": self.updated_at.timestamp() if self.updated_at else None, "aliases": self.aliases, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "has_geo_json": True if self.simplified_geom else False, } if not light: # avoiding joins here res["groups"] = [ group.as_dict(with_counts=False) for group in self.groups.all() ] res["org_unit_type_name"] = self.org_unit_type.name if self.org_unit_type else None res["org_unit_type"] = self.org_unit_type.as_dict( ) if self.org_unit_type else None res["source"] = self.version.data_source.name if self.version else None res["source_id"] = self.version.data_source.id if self.version else None res["version"] = self.version.number if self.version else None if hasattr(self, "search_index"): res["search_index"] = self.search_index return res def as_small_dict(self): res = { "name": self.name, "id": self.id, "parent_id": self.parent_id, "validation_status": self.validation_status, "parent_name": self.parent.name if self.parent else None, "source": self.version.data_source.name if self.version else None, "source_ref": self.source_ref, "parent": self.parent.as_small_dict() if self.parent else None, "org_unit_type_name": self.org_unit_type.name if self.org_unit_type else None, } if hasattr(self, "search_index"): res["search_index"] = self.search_index return res def as_dict_for_csv(self): return { "name": self.name, "id": self.id, "source_ref": self.source_ref, "parent_id": self.parent_id, "org_unit_type": self.org_unit_type.name, } def as_location(self): res = { "id": self.id, "name": self.name, "short_name": self.name, "latitude": self.location.y if self.location else None, "longitude": self.location.x if self.location else None, "altitude": self.location.z if self.location else None, "has_geo_json": True if self.simplified_geom else False, "org_unit_type": self.org_unit_type.name if self.org_unit_type else None, "org_unit_type_depth": self.org_unit_type.depth if self.org_unit_type else None, "source_id": self.version.data_source.id if self.version else None, "source_name": self.version.data_source.name if self.version else None, } if hasattr(self, "search_index"): res["search_index"] = self.search_index return res def source_path(self): """DHIS2-friendly path built using source refs""" path_components = [] cur = self while cur: if cur.source_ref: path_components.insert(0, cur.source_ref) cur = cur.parent if len(path_components) > 0: return "/" + ("/".join(path_components)) return None
class Migration(migrations.Migration): initial = True dependencies = [("people", "0029_person_mandates")] operations = [ migrations.CreateModel( name="Payment", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "created", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="created", ), ), ( "modified", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="modified", ), ), ( "coordinates", PointField( blank=True, geography=True, null=True, srid=4326, verbose_name="coordonnées", ), ), ( "coordinates_type", models.PositiveSmallIntegerField( choices=[ (0, "Coordonnées manuelles"), (10, "Coordonnées automatiques précises"), ( 20, "Coordonnées automatiques approximatives (niveau rue)", ), (30, "Coordonnées automatiques approximatives (ville)" ), (50, "Coordonnées automatiques (qualité inconnue)"), (255, "Coordonnées introuvables"), ], editable=False, help_text= "Comment les coordonnées ci-dessus ont-elle été acquises", null=True, verbose_name="type de coordonnées", ), ), ( "location_name", models.CharField(blank=True, max_length=255, verbose_name="nom du lieu"), ), ( "location_address1", models.CharField(blank=True, max_length=100, verbose_name="adresse (1ère ligne)"), ), ( "location_address2", models.CharField(blank=True, max_length=100, verbose_name="adresse (2ème ligne)"), ), ( "location_city", models.CharField(blank=True, max_length=100, verbose_name="ville"), ), ( "location_zip", models.CharField(blank=True, max_length=20, verbose_name="code postal"), ), ( "location_state", models.CharField(blank=True, max_length=40, verbose_name="état"), ), ( "location_country", django_countries.fields.CountryField(blank=True, max_length=2, verbose_name="pays"), ), ( "location_address", models.CharField( blank=True, help_text= "L'adresse telle qu'elle a éventuellement été copiée depuis NationBuilder. Ne plus utiliser.", max_length=255, verbose_name="adresse complète", ), ), ("email", models.EmailField(max_length=255, verbose_name="email")), ("first_name", models.CharField(max_length=255, verbose_name="prénom")), ( "last_name", models.CharField(max_length=255, verbose_name="nom de famille"), ), ( "type", models.CharField( choices=[ ("don", "don"), ("inscription à un événement", "événement"), ], max_length=255, verbose_name="type", ), ), ("price", models.IntegerField(verbose_name="prix en centimes d'euros")), ( "status", models.IntegerField( choices=[ (0, "En attente"), (1, "Terminé"), (2, "Abandonné"), (3, "Annulé"), (4, "Refusé"), ], default=0, verbose_name="status", ), ), ( "meta", django.contrib.postgres.fields.jsonb.JSONField( blank=True, default=dict), ), ( "systempay_responses", django.contrib.postgres.fields.jsonb.JSONField( blank=True, default=list), ), ( "person", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to="people.Person"), ), ], options={"abstract": False}, ) ]
class Migration(migrations.Migration): initial = True dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( name="Person", fields=[ ( "created", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="created", ), ), ( "modified", models.DateTimeField( default=django.utils.timezone.now, editable=False, verbose_name="modified", ), ), ( "id", models.UUIDField( default=uuid.uuid4, help_text="UUID interne à l'API pour identifier la ressource", primary_key=True, serialize=False, verbose_name="UUID", ), ), ( "nb_id", models.IntegerField( blank=True, help_text="L'identifiant de la ressource correspondante sur NationBuilder, si importé.", null=True, unique=True, verbose_name="ID sur NationBuilder", ), ), ( "coordinates", PointField( blank=True, geography=True, null=True, srid=4326, verbose_name="coordonnées", ), ), ( "location_name", models.CharField( blank=True, max_length=255, verbose_name="nom du lieu" ), ), ( "location_address", models.CharField( blank=True, max_length=255, verbose_name="adresse complète" ), ), ( "location_address1", models.CharField( blank=True, max_length=100, verbose_name="adresse (1ère ligne)" ), ), ( "location_address2", models.CharField( blank=True, max_length=100, verbose_name="adresse (2ème ligne)" ), ), ( "location_city", models.CharField(blank=True, max_length=100, verbose_name="ville"), ), ( "location_zip", models.CharField( blank=True, max_length=20, verbose_name="code postal" ), ), ( "location_state", models.CharField(blank=True, max_length=40, verbose_name="état"), ), ( "location_country", django_countries.fields.CountryField( blank=True, max_length=2, verbose_name="pays" ), ), ( "email", models.EmailField( help_text="L'adresse email de la personne, utilisée comme identifiant", max_length=254, unique=True, verbose_name="adresse email", ), ), ( "subscribed", models.BooleanField( default=True, help_text="L'utilisateur souhaite-t-il recevoir les newsletters ?", verbose_name="inscrit à la newsletter", ), ), ( "first_name", models.CharField(blank=True, max_length=255, verbose_name="prénom"), ), ( "last_name", models.CharField( blank=True, max_length=255, verbose_name="nom de famille" ), ), ( "bounced", models.BooleanField( default=False, help_text="Indique que des mails envoyés ont été rejetés par le serveur distant", verbose_name="email rejeté", ), ), ( "bounced_date", models.DateTimeField( blank=True, help_text="Si des mails ont été rejetés, indique la date du dernier rejet", null=True, verbose_name="date de rejet de l'email", ), ), ( "role", models.OneToOneField( on_delete=django.db.models.deletion.PROTECT, related_name="person", to=settings.AUTH_USER_MODEL, ), ), ], options={ "verbose_name": "personne", "verbose_name_plural": "personnes", "ordering": ("-created",), "default_permissions": ("add", "change", "delete", "view"), }, ), migrations.CreateModel( name="PersonTag", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "label", models.CharField(max_length=50, unique=True, verbose_name="nom"), ), ( "description", models.TextField(blank=True, verbose_name="description"), ), ], options={"verbose_name": "tag"}, ), migrations.AddField( model_name="person", name="tags", field=models.ManyToManyField( blank=True, related_name="people", to="people.PersonTag" ), ), ]