Add App Contracts
This commit is contained in:
@@ -19,6 +19,7 @@ INSTALLED_APPS = [
|
|||||||
"rest_framework_api_key",
|
"rest_framework_api_key",
|
||||||
'socials',
|
'socials',
|
||||||
'events',
|
'events',
|
||||||
|
'contracts',
|
||||||
'config',
|
'config',
|
||||||
# 'academia_nuts',
|
# 'academia_nuts',
|
||||||
# 'leg_info',
|
# 'leg_info',
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from django.urls import path, include
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('socials/', include('socials.urls')),
|
path('socials/', include('socials.urls')),
|
||||||
path('events/', include('events.urls')),
|
path('events/', include('events.urls')),
|
||||||
|
path('contracts/', include('contracts.urls')),
|
||||||
path('digimon/', admin.site.urls),
|
path('digimon/', admin.site.urls),
|
||||||
] + static (settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
|
] + static (settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
|
||||||
# + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
# + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
|||||||
0
contracts/__init__.py
Normal file
0
contracts/__init__.py
Normal file
15
contracts/admin.py
Normal file
15
contracts/admin.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
class ContractAdmin(admin.ModelAdmin):
|
||||||
|
# prepopulated_fields = {"slug": ("shortname",)}
|
||||||
|
list_display = ("notice_id", "pub_date")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
admin.site.register(Paragraph)
|
||||||
|
admin.site.register(OriginalContract)
|
||||||
|
admin.site.register(Contract, ContractAdmin)
|
||||||
|
admin.site.register(Company)
|
||||||
|
|
||||||
6
contracts/apps.py
Normal file
6
contracts/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ContractsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'contracts'
|
||||||
415
contracts/digitools.py
Normal file
415
contracts/digitools.py
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
import os, sys
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from dateutil import relativedelta
|
||||||
|
from time import sleep
|
||||||
|
import pytz
|
||||||
|
from lxml import html
|
||||||
|
from pprint import pprint as ppr
|
||||||
|
|
||||||
|
import django
|
||||||
|
|
||||||
|
from xvfbwrapper import Xvfb
|
||||||
|
from selenium import webdriver as wd
|
||||||
|
|
||||||
|
from events.models import Event as DSEvent, Organization, Promo, Scraper, Calendar
|
||||||
|
|
||||||
|
# tz = pytz.timezone("US/Central")
|
||||||
|
plus_one_month = relativedelta.relativedelta(months=1)
|
||||||
|
odt_next_month = datetime.now() + plus_one_month
|
||||||
|
|
||||||
|
def translateMonth(month):
|
||||||
|
MONTHS = [
|
||||||
|
('Januar', 'JÄN', 'January'),
|
||||||
|
('Februar', 'FEBR', 'February'),
|
||||||
|
('März', 'MRZ', 'March'),
|
||||||
|
('April', 'APR', 'April'),
|
||||||
|
('Mai', 'MAI', 'May'),
|
||||||
|
('Juni', 'JUN', 'June'),
|
||||||
|
('Juli', 'JUL', 'July'),
|
||||||
|
('August', 'AUG', 'August'),
|
||||||
|
('September', 'SEP', 'September'),
|
||||||
|
('Oktober', 'OKT', 'October'),
|
||||||
|
('November', 'NOV', 'November'),
|
||||||
|
('Dezember', 'DEZ', 'December'),
|
||||||
|
]
|
||||||
|
for mon in MONTHS:
|
||||||
|
if month == mon[1]:
|
||||||
|
return mon[2]
|
||||||
|
|
||||||
|
# Get Scraper name, item count and online_calendar (virtcal)
|
||||||
|
def getScraper(venue, website, cal):
|
||||||
|
virtcal = Calendar.objects.get(shortcode='000')
|
||||||
|
ncal = Calendar.objects.get(shortcode=cal)
|
||||||
|
try:
|
||||||
|
scraper, created = Scraper.objects.get_or_create(
|
||||||
|
name=venue.name,
|
||||||
|
website=website,
|
||||||
|
calendar = ncal,
|
||||||
|
items = 0,
|
||||||
|
new_items = 0,
|
||||||
|
last_ran = datetime.now(),
|
||||||
|
)
|
||||||
|
venue.cal = ncal
|
||||||
|
venue.save()
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
scraper = Scraper.objects.get(name=venue.name)
|
||||||
|
num_of_events = DSEvent.objects.filter(scraper=scraper)
|
||||||
|
scraper.items = len(num_of_events)
|
||||||
|
scraper.save()
|
||||||
|
print("Scraper: ", scraper)
|
||||||
|
return scraper, scraper.items, virtcal
|
||||||
|
|
||||||
|
# Update item_count of the Scraper at the end of the scrape
|
||||||
|
def updateScraper(scraper, item_count_start):
|
||||||
|
num_of_events = DSEvent.objects.filter(scraper=scraper)
|
||||||
|
scraper.items = len(num_of_events)
|
||||||
|
scraper.new_items = len(num_of_events) - item_count_start
|
||||||
|
scraper.last_ran = datetime.now()
|
||||||
|
scraper.save()
|
||||||
|
print("Scaper Updated")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get site HTML content for XPATH travel
|
||||||
|
def getSource(browser, link):
|
||||||
|
browser.get(link)
|
||||||
|
sleep(6)
|
||||||
|
ps = html.fromstring(browser.page_source)
|
||||||
|
return ps
|
||||||
|
|
||||||
|
# Get Selenium Web Driver, with params for Chrome or Firefox
|
||||||
|
# Or in production to run headless
|
||||||
|
def getBrowser(run_env):
|
||||||
|
if run_env == 'dev':
|
||||||
|
print("Chrome is a go!")
|
||||||
|
br = wd.Chrome()
|
||||||
|
return br
|
||||||
|
elif run_env == "def":
|
||||||
|
print("Firefox go vroom")
|
||||||
|
br = wd.Firefox()
|
||||||
|
return br
|
||||||
|
elif run_env == "prod":
|
||||||
|
start_cmd = "Xvfb :91 && export DISPLAY=:91 &"
|
||||||
|
xvfb = Xvfb()
|
||||||
|
os.system(start_cmd)
|
||||||
|
xvfb.start()
|
||||||
|
print("started Xvfb")
|
||||||
|
br = wd.Firefox()
|
||||||
|
return br
|
||||||
|
else:
|
||||||
|
print("Failed", sys.argv, arg1)
|
||||||
|
quit()
|
||||||
|
|
||||||
|
# Create Dated URL with zero-padded numbers
|
||||||
|
def createBasicURL(site_url):
|
||||||
|
month = datetime.now().month
|
||||||
|
next_month = odt_next_month.month
|
||||||
|
year = datetime.now().year
|
||||||
|
if next_month == 1:
|
||||||
|
next_year = year+1
|
||||||
|
links = [
|
||||||
|
site_url + str(month) + "/" + str(year),
|
||||||
|
site_url + str(next_month) + "/" + str(next_year)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
links = [
|
||||||
|
site_url + str(month) + "/" + str(year),
|
||||||
|
site_url + str(next_month) + "/" + str(year)
|
||||||
|
]
|
||||||
|
return links
|
||||||
|
|
||||||
|
# Create Dated URL without zero-padded numbers
|
||||||
|
def createURLNoZero(site_url):
|
||||||
|
month = datetime.now().month
|
||||||
|
next_month = odt_next_month.month
|
||||||
|
year = datetime.now().year
|
||||||
|
links = [
|
||||||
|
site_url + str(year) + "/" + str(month),
|
||||||
|
]
|
||||||
|
if next_month == "1":
|
||||||
|
links.append(site_url + str(int(year)+1) + "/" + str(next_month))
|
||||||
|
else:
|
||||||
|
links.append(site_url + str(year) + "/" + str(next_month))
|
||||||
|
return links
|
||||||
|
|
||||||
|
# Create Dated URL Link with zero-padding
|
||||||
|
def createURL(site_url):
|
||||||
|
month = datetime.now().month
|
||||||
|
if month < 10:
|
||||||
|
month = "0" + str(month)
|
||||||
|
else:
|
||||||
|
month = str(month)
|
||||||
|
next_month = odt_next_month.month
|
||||||
|
if next_month < 10:
|
||||||
|
next_month = "0" + str(next_month)
|
||||||
|
else:
|
||||||
|
next_month = str(next_month)
|
||||||
|
year = datetime.now().year
|
||||||
|
links = [
|
||||||
|
site_url + str(year) + "/" + month,
|
||||||
|
]
|
||||||
|
if next_month == "01":
|
||||||
|
links.append(site_url + str(int(year)+1) + "/" + next_month)
|
||||||
|
else:
|
||||||
|
links.append(site_url + str(year) + "/" + next_month)
|
||||||
|
return links
|
||||||
|
|
||||||
|
# Create Dated URL with dashes
|
||||||
|
def createDashURL(site_url):
|
||||||
|
month = datetime.now().month
|
||||||
|
if month < 10:
|
||||||
|
month = "0" + str(month)
|
||||||
|
else:
|
||||||
|
month = str(month)
|
||||||
|
next_month = odt.month
|
||||||
|
if next_month < 10:
|
||||||
|
next_month = "0" + str(next_month)
|
||||||
|
else:
|
||||||
|
next_month = str(next_month)
|
||||||
|
year = datetime.now().year
|
||||||
|
links = [
|
||||||
|
site_url + month + "-" + str(year),
|
||||||
|
site_url + next_month + "-" + str(year)
|
||||||
|
]
|
||||||
|
print(links)
|
||||||
|
return links
|
||||||
|
|
||||||
|
# Add Calendar to Event Object (maybe extraneous)
|
||||||
|
def add_calendar(event, calendar):
|
||||||
|
# print("Add Calendar", type(event), event, calendar)
|
||||||
|
if type(event) is tuple:
|
||||||
|
event = event[0]
|
||||||
|
cal = Calendar.objects.get(shortcode=calendar)
|
||||||
|
event.calendar.add(cal)
|
||||||
|
event.save()
|
||||||
|
return event
|
||||||
|
|
||||||
|
# Add Calendars to Event Object ??
|
||||||
|
def add_calendars(event, data):
|
||||||
|
if type(data['calendars']) is not list:
|
||||||
|
event.calendar.add(data['calendars'])
|
||||||
|
else:
|
||||||
|
for cal in data['calendars']:
|
||||||
|
event.calendar.add(cal)
|
||||||
|
event.save()
|
||||||
|
return event
|
||||||
|
|
||||||
|
# Create Basic DigiSnaxx Event
|
||||||
|
def createBasicEvent(event, event_type, venue):
|
||||||
|
try:
|
||||||
|
new_event, created = DSEvent.objects.update_or_create(
|
||||||
|
event_type = event_type,
|
||||||
|
show_title = event['title'],
|
||||||
|
show_link = event['link'],
|
||||||
|
show_date = event['dateStamp'],
|
||||||
|
scraper = event['scraper'],
|
||||||
|
venue = venue
|
||||||
|
)
|
||||||
|
new_event = add_calendars(new_event, event)
|
||||||
|
print("\n+new event+")
|
||||||
|
return new_event, created
|
||||||
|
except Exception as e:
|
||||||
|
print("DT Error: ", e)
|
||||||
|
ppr(event)
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
# Create iCal Event
|
||||||
|
def createBasiciCalEvent(event, event_type, venue):
|
||||||
|
new_event, created = DSEvent.objects.update_or_create(
|
||||||
|
event_type = event_type,
|
||||||
|
show_title = event['title'][0],
|
||||||
|
show_link = event['link'],
|
||||||
|
show_date = datetime.strptime(str(event['dateStamp'][0]), '%Y-%m-%d %H:%M:%S%z %Z'),
|
||||||
|
scraper = event['scraper'],
|
||||||
|
venue = venue
|
||||||
|
)
|
||||||
|
new_event = add_calendars(new_event, event)
|
||||||
|
print("Success")
|
||||||
|
return new_event, created
|
||||||
|
|
||||||
|
def createDetailedEvent2(event, event_type, venue, scraper):
|
||||||
|
new_event, created = DSEvent.objects.update_or_create(
|
||||||
|
event_type = event_type,
|
||||||
|
show_title = event["show_title"],
|
||||||
|
show_link = event["link"],
|
||||||
|
show_date = event["dateStamp"],
|
||||||
|
more_details = event["details"],
|
||||||
|
scraper = event['scraper'],
|
||||||
|
venue = venue
|
||||||
|
)
|
||||||
|
new_event = add_calendars(new_event, event)
|
||||||
|
print("Success")
|
||||||
|
return new_event, created
|
||||||
|
|
||||||
|
# Create Detailed Event with Details & Guests
|
||||||
|
# Details in JSON Format
|
||||||
|
def createDetailedEvent(event, event_type, venue, scraper):
|
||||||
|
new_event, created = DSEvent.objects.update_or_create(
|
||||||
|
event_type = event_type,
|
||||||
|
show_title = event["show_title"],
|
||||||
|
show_link = event["link"],
|
||||||
|
show_date = event["dateStamp"],
|
||||||
|
guests = " ".join(event["guests"]),
|
||||||
|
more_details = event["details"],
|
||||||
|
scraper = event['scraper'],
|
||||||
|
venue = venue
|
||||||
|
)
|
||||||
|
new_event = add_calendars(new_event, event)
|
||||||
|
print("Success")
|
||||||
|
return new_event, created
|
||||||
|
|
||||||
|
# Create iCal event from DF_Online & Medellin
|
||||||
|
def createCleanIcalEvent(event, scraper, venue, event_type):
|
||||||
|
new_date = event['eventDate']
|
||||||
|
new_event = {}
|
||||||
|
new_event['scraper'] = scraper
|
||||||
|
new_event['calendars'] = scraper.calendar
|
||||||
|
new_event['title'] = event['strSummary'],
|
||||||
|
new_event['date'] = str(new_date),
|
||||||
|
new_event['dateStamp'] = str(new_date),
|
||||||
|
new_event['link'] = venue.website
|
||||||
|
print("New Event")
|
||||||
|
# ppr(new_event)
|
||||||
|
createBasiciCalEvent(new_event, event_type, venue)
|
||||||
|
|
||||||
|
# Get events from iCal
|
||||||
|
def getiCalEvents(gcal, scraper, venue, event_type):
|
||||||
|
events = []
|
||||||
|
for component in gcal.walk():
|
||||||
|
event = {}
|
||||||
|
event['scraper'] = scraper
|
||||||
|
event['calendars'] = [scraper.calendar]
|
||||||
|
event['strSummary'] = f"{(component.get('SUMMARY'))}"
|
||||||
|
event['strDesc'] = component.get('DESCRIPTION')
|
||||||
|
event['strLocation'] = component.get('LOCATION')
|
||||||
|
event['dateStart'] = component.get('DTSTART')
|
||||||
|
event['dateStamp'] = component.get('DTSTAMP')
|
||||||
|
if event['dateStamp'] is not None:
|
||||||
|
event['dateStamp'] = event['dateStamp'].dt
|
||||||
|
if event['dateStart'] is not None:
|
||||||
|
try:
|
||||||
|
event['dateStart'] = event['dateStart'].dt
|
||||||
|
except Exception as e:
|
||||||
|
print("what? ", e)
|
||||||
|
|
||||||
|
if event['strSummary'] != 'None':
|
||||||
|
event['details'] = {
|
||||||
|
"description" : event['strDesc'],
|
||||||
|
"Location" : event['strLocation'],
|
||||||
|
}
|
||||||
|
events.append(event)
|
||||||
|
return events
|
||||||
|
|
||||||
|
# Build iCal Events and Send to Create
|
||||||
|
def buildiCalEvents(events, event_type, scraper, venue):
|
||||||
|
for event in events:
|
||||||
|
e = {}
|
||||||
|
e['calendars'] = event['calendars']
|
||||||
|
try:
|
||||||
|
e['dateStamp'] = event['dateStart'][0]
|
||||||
|
except:
|
||||||
|
e['dateStamp'] = event['dateStart']
|
||||||
|
e['title'] = event['strSummary']
|
||||||
|
e['scraper'] = scraper
|
||||||
|
e['link'] = venue.website
|
||||||
|
try:
|
||||||
|
createBasicEvent(e, event_type, venue)
|
||||||
|
scraper.items+=1
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: ", e)
|
||||||
|
scraper.save()
|
||||||
|
return
|
||||||
|
|
||||||
|
def getMDEVenue(venue, event):
|
||||||
|
if venue.name == "DANCEFREE":
|
||||||
|
venue.website = "https://www.instagram.com/dancefreeco"
|
||||||
|
if venue.name == "Vintrash":
|
||||||
|
venue.website = "https://www.instagram.com/vintrashbar"
|
||||||
|
if venue.name == "The Wandering Paisa":
|
||||||
|
venue.website = "https://wanderingpaisahostel.com"
|
||||||
|
if venue.name == "Dulce Posion":
|
||||||
|
venue.website = "https://www.instagram.com/dulceposionr"
|
||||||
|
if venue.name == "Blood Dance Company":
|
||||||
|
venue.website = "https://www.instagram.com/blooddancecompany"
|
||||||
|
if venue.name == "OLSA Certified Spanish School":
|
||||||
|
venue.website = "https://www.olsafoundation.org/"
|
||||||
|
if event['strSummary'] == "Merli Rooftop Language Exchange":
|
||||||
|
venue.website = "https://calendar.google.com/calendar/embed?src=46ae0446724b1b3ee83cbd7dbc0db6a235bf97509ad860ca91eada3c267b5e41%40group.calendar.google.com&ctz=America%2FBogota"
|
||||||
|
if "Concious Warrior" in event['strSummary']:
|
||||||
|
venue.website = "https://www.consciouscolombia.com/"
|
||||||
|
venue.save()
|
||||||
|
print(venue)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get iCal events for Medellin & OnlineEvents
|
||||||
|
def getiCalRepeateEvents(gcal, scraper, venue, event_type, cal):
|
||||||
|
for component in gcal.walk():
|
||||||
|
event = {}
|
||||||
|
event['scraper'] = scraper
|
||||||
|
event['calendars'] = [scraper.calendar]
|
||||||
|
event['strSummary'] = f"{(component.get('SUMMARY'))}"
|
||||||
|
event['strDesc'] = component.get('DESCRIPTION')
|
||||||
|
event['strLocation'] = str(component.get('LOCATION'))
|
||||||
|
event['dateStart'] = component.get('DTSTART')
|
||||||
|
event['dateStamp'] = component.get('DTSTAMP')
|
||||||
|
if event['strSummary'] != 'None':
|
||||||
|
event['details'] = {
|
||||||
|
"description" : event['strDesc'],
|
||||||
|
"Location" : event['strLocation'],
|
||||||
|
}
|
||||||
|
if event['dateStamp'] != None:
|
||||||
|
event['dateStart'] = event['dateStart'].dt
|
||||||
|
event['dateStart'] = datetime.strptime(str(event['dateStart']) + " UTC", '%Y-%m-%d %H:%M:%S%z %Z')
|
||||||
|
event['timezone'] = str(event['dateStart'])[-6:].strip()
|
||||||
|
rules = component.get('RRule')
|
||||||
|
try:
|
||||||
|
if rules['FREQ'][0] == 'WEEKLY':
|
||||||
|
date = datetime.today().date() - timedelta(days=datetime.today().weekday())
|
||||||
|
date = datetime.combine(date, event['dateStart'].time())
|
||||||
|
days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]
|
||||||
|
event = splitLocation(event, city="Medellin")
|
||||||
|
for day in rules['BYDAY']:
|
||||||
|
nday = days.index(day)
|
||||||
|
if cal == 'mde':
|
||||||
|
getMDEVenue(event['venue'],event)
|
||||||
|
print(event)
|
||||||
|
iCalEventRepeatFilter(nday, date, event, scraper, event['venue'], "Ed")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: ", e, "\n\n")
|
||||||
|
# ppr(event)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def iCalEventRepeatFilter(day, date, event, scraper, venue, event_type):
|
||||||
|
print("repeate events")
|
||||||
|
days = [day-1, day+6, day+13]
|
||||||
|
for day in days:
|
||||||
|
event['dateStamp'] = date + timedelta(days=day)
|
||||||
|
dateStart = str(event['dateStamp']) + event['timezone'] + ' UTC'
|
||||||
|
event['eventDate'] = dateStart
|
||||||
|
createCleanIcalEvent(event, scraper, venue, event_type)
|
||||||
|
return
|
||||||
|
|
||||||
|
def splitLocation(event, **kwargs):
|
||||||
|
loc_split = event['strLocation'].split(',')
|
||||||
|
# ppr(loc_split)
|
||||||
|
venue_name = loc_split[0]
|
||||||
|
venue, created = Organization.objects.get_or_create(
|
||||||
|
name=venue_name,
|
||||||
|
)
|
||||||
|
event['venue'] = venue
|
||||||
|
if kwargs['city']:
|
||||||
|
venue.city = kwargs['city']
|
||||||
|
venue.save()
|
||||||
|
return event
|
||||||
|
|
||||||
|
# ARCHIVED Methods
|
||||||
|
def createBasicArticle(article, event_type, organization):
|
||||||
|
new_article, created = Promo.objects.update_or_create(
|
||||||
|
promo_type = 'Ja',
|
||||||
|
title = article['title'],
|
||||||
|
target_link = article['link'],
|
||||||
|
published = True,
|
||||||
|
organization = organization
|
||||||
|
)
|
||||||
|
return new_article, created
|
||||||
95
contracts/migrations/0001_initial.py
Normal file
95
contracts/migrations/0001_initial.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 19:41
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tags',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=31, unique=True)),
|
||||||
|
('desc', models.TextField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Company',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=63)),
|
||||||
|
('unq_entity_id', models.CharField(blank=True, max_length=63, null=True)),
|
||||||
|
('website', models.URLField(blank=True, max_length=127, null=True)),
|
||||||
|
('short_desc', models.CharField(blank=True, max_length=63, null=True)),
|
||||||
|
('long_desc', models.TextField(blank=True, null=True)),
|
||||||
|
('gmap_link', models.CharField(blank=True, max_length=253, null=True)),
|
||||||
|
('address_complete', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('address_numbers', models.CharField(blank=True, max_length=63, null=True)),
|
||||||
|
('address_type', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('city', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('state', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('zip_code', models.CharField(blank=True, max_length=15, null=True)),
|
||||||
|
('tags', models.ManyToManyField(blank=True, to='contracts.tags')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Companies',
|
||||||
|
'ordering': ['name'],
|
||||||
|
'unique_together': {('name', 'website')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Contract',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(max_length=31, unique=True)),
|
||||||
|
('notice_id', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('related_notice_id', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('opp_type', models.CharField(blank=True, max_length=63, null=True)),
|
||||||
|
('pub_date', models.DateField(blank=True, null=True)),
|
||||||
|
('us_dept', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('us_dept_sub_tier', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('major_dept', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('us_office', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('award_date', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('award_num', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('unq_entity_id', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('awarded_name', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('awarded_addr', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('contract_value', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('orig_set_aside', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('prod_svc_code', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('naics_code', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('contract_url', models.CharField(blank=True, max_length=127, null=True)),
|
||||||
|
('description', models.TextField(blank=True, null=True)),
|
||||||
|
('company', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.company')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Contracts',
|
||||||
|
'ordering': ['pub_date', 'notice_id'],
|
||||||
|
'unique_together': {('notice_id', 'unq_entity_id')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Exec',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=63)),
|
||||||
|
('linkedin', models.URLField(blank=True, max_length=127, null=True)),
|
||||||
|
('short_desc', models.CharField(blank=True, max_length=63, null=True)),
|
||||||
|
('company', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.company')),
|
||||||
|
('tags', models.ManyToManyField(blank=True, to='contracts.tags')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name_plural': 'Execs',
|
||||||
|
'ordering': ['name'],
|
||||||
|
'unique_together': {('name', 'company')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 19:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='contract',
|
||||||
|
name='pub_date_txt',
|
||||||
|
field=models.CharField(blank=True, max_length=63, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='pub_date',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
contracts/migrations/0003_alter_contract_company.py
Normal file
19
contracts/migrations/0003_alter_contract_company.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 20:08
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0002_contract_pub_date_txt_alter_contract_pub_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='company',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contracts.company'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
contracts/migrations/0004_alter_contract_notice_id.py
Normal file
19
contracts/migrations/0004_alter_contract_notice_id.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 20:09
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0003_alter_contract_company'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='notice_id',
|
||||||
|
field=models.CharField(default='000000000000000', max_length=31),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
18
contracts/migrations/0005_alter_contract_title.py
Normal file
18
contracts/migrations/0005_alter_contract_title.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 20:12
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0004_alter_contract_notice_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=31),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 23:04
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0005_alter_contract_title'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='contract',
|
||||||
|
options={'ordering': ['-pub_date', 'notice_id'], 'verbose_name_plural': 'Contracts'},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contract',
|
||||||
|
name='awarded_addr',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contract',
|
||||||
|
name='awarded_name',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='unq_entity_id',
|
||||||
|
field=models.CharField(blank=True, max_length=63, null=True, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
contracts/migrations/0007_alter_company_unq_entity_id.py
Normal file
18
contracts/migrations/0007_alter_company_unq_entity_id.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 23:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0006_alter_contract_options_remove_contract_awarded_addr_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='unq_entity_id',
|
||||||
|
field=models.CharField(max_length=63, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
contracts/migrations/0008_alter_contract_award_date.py
Normal file
18
contracts/migrations/0008_alter_contract_award_date.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 23:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0007_alter_company_unq_entity_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='award_date',
|
||||||
|
field=models.DateField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 23:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0008_alter_contract_award_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='contract',
|
||||||
|
unique_together={('notice_id', 'unq_entity_id', 'pub_date_txt')},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=254),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-19 02:20
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0009_alter_contract_unique_together_alter_contract_title'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OriginalContract',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('number', models.CharField(max_length=31, unique=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Paragraph',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('date', models.DateField(blank=True, null=True)),
|
||||||
|
('link', models.CharField(max_length=255, unique=True)),
|
||||||
|
('paragraph', models.TextField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contract',
|
||||||
|
name='award_date',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='contract',
|
||||||
|
name='original_contract_number',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contracts.originalcontract'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='originalcontract',
|
||||||
|
name='para',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.paragraph'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-19 02:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0010_originalcontract_paragraph_alter_contract_award_date_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='paragraph',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='paragraph',
|
||||||
|
name='link',
|
||||||
|
field=models.CharField(max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='paragraph',
|
||||||
|
name='paragraph',
|
||||||
|
field=models.TextField(),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
contracts/migrations/0012_alter_originalcontract_number.py
Normal file
18
contracts/migrations/0012_alter_originalcontract_number.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-19 02:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0011_alter_paragraph_date_alter_paragraph_link_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='originalcontract',
|
||||||
|
name='number',
|
||||||
|
field=models.CharField(max_length=63),
|
||||||
|
),
|
||||||
|
]
|
||||||
17
contracts/migrations/0013_alter_contract_unique_together.py
Normal file
17
contracts/migrations/0013_alter_contract_unique_together.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-19 02:51
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0012_alter_originalcontract_number'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='contract',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
]
|
||||||
17
contracts/migrations/0014_alter_paragraph_options.py
Normal file
17
contracts/migrations/0014_alter_paragraph_options.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-19 08:50
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('contracts', '0013_alter_contract_unique_together'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='paragraph',
|
||||||
|
options={'ordering': ['-date'], 'verbose_name_plural': 'Paragraphs'},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
contracts/migrations/__init__.py
Normal file
0
contracts/migrations/__init__.py
Normal file
139
contracts/models.py
Normal file
139
contracts/models.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.core.files.storage import FileSystemStorage
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class Paragraph(models.Model):
|
||||||
|
date = models.DateField(blank=False, null=False, unique=False)
|
||||||
|
link = models.CharField(max_length=255, unique=False)
|
||||||
|
paragraph = models.TextField(blank=False, null=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name_plural = "Paragraphs"
|
||||||
|
ordering = ['-date']
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.date
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.date
|
||||||
|
|
||||||
|
|
||||||
|
class OriginalContract(models.Model):
|
||||||
|
number = models.CharField(max_length=63, unique=False)
|
||||||
|
para = models.ForeignKey(Paragraph, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.number
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.number
|
||||||
|
|
||||||
|
|
||||||
|
class Tags(models.Model):
|
||||||
|
name = models.CharField(max_length=31, unique=True)
|
||||||
|
desc = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Tags(models.Model):
|
||||||
|
name = models.CharField(max_length=31, unique=True)
|
||||||
|
desc = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Company(models.Model):
|
||||||
|
name = models.CharField(max_length=63)
|
||||||
|
unq_entity_id = models.CharField(max_length=63, blank=False, null=False, unique=True)
|
||||||
|
website = models.URLField(max_length=127, blank=True, null=True)
|
||||||
|
short_desc = models.CharField(max_length=63, blank=True, null=True)
|
||||||
|
long_desc = models.TextField(blank=True, null=True)
|
||||||
|
gmap_link = models.CharField(max_length=253, blank=True, null=True)
|
||||||
|
tags = models.ManyToManyField(Tags, blank=True)
|
||||||
|
|
||||||
|
address_complete = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
address_numbers = models.CharField(max_length=63, blank=True, null=True)
|
||||||
|
address_type = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
city = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
state = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
zip_code = models.CharField(max_length=15, blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ("name", "website")
|
||||||
|
verbose_name_plural = "Companies"
|
||||||
|
ordering = ['name']
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Exec(models.Model):
|
||||||
|
name = models.CharField(max_length=63)
|
||||||
|
company = models.ForeignKey(Company, on_delete=models.CASCADE)
|
||||||
|
linkedin = models.URLField(max_length=127, blank=True, null=True)
|
||||||
|
short_desc = models.CharField(max_length=63, blank=True, null=True)
|
||||||
|
tags = models.ManyToManyField(Tags, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ("name", "company")
|
||||||
|
verbose_name_plural = "Execs"
|
||||||
|
ordering = ['name']
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Contract(models.Model):
|
||||||
|
title = models.CharField(max_length=254, unique=False)
|
||||||
|
original_contract_number = models.ForeignKey(OriginalContract, on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
company = models.ForeignKey(Company, blank=True, null=True, on_delete=models.CASCADE)
|
||||||
|
notice_id = models.CharField(max_length=31, blank=False, null=False)
|
||||||
|
related_notice_id = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
opp_type = models.CharField(max_length=63, blank=True, null=True)
|
||||||
|
pub_date = models.DateTimeField(blank=True, null=True)
|
||||||
|
pub_date_txt = models.CharField(max_length=63, blank=True, null=True)
|
||||||
|
us_dept = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
us_dept_sub_tier = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
major_dept = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
us_office = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
award_date = models.DateField(blank=True, null=True)
|
||||||
|
award_num = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
unq_entity_id = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
contract_value = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
orig_set_aside = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
prod_svc_code = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
naics_code = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
contract_url = models.CharField(max_length=127, blank=True, null=True)
|
||||||
|
description = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
# unique_together = ("notice_id", "unq_entity_id", "pub_date_txt")
|
||||||
|
verbose_name_plural = "Contracts"
|
||||||
|
ordering = ['-pub_date', 'notice_id']
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return "%s" % self.notice_id
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return u'%s' % self.notice_id
|
||||||
27
contracts/serializers.py
Normal file
27
contracts/serializers.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from .models import *
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework.permissions import BasePermission
|
||||||
|
|
||||||
|
############
|
||||||
|
## Events ##
|
||||||
|
############
|
||||||
|
|
||||||
|
|
||||||
|
class CompanySerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Company
|
||||||
|
# fields = ('id', 'name', 'website', 'city', 'latitude', 'longitude', 'has_map')
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class ContractSerializer(serializers.ModelSerializer):
|
||||||
|
company = CompanySerializer(many=False)
|
||||||
|
# target_language = serializers.SerializerMethodField()
|
||||||
|
class Meta:
|
||||||
|
model = Contract
|
||||||
|
fields = '__all__'
|
||||||
|
depth = 2
|
||||||
|
# fields = ('id', 'name',)
|
||||||
3
contracts/tests.py
Normal file
3
contracts/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
26
contracts/urls.py
Normal file
26
contracts/urls.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
"""ds_events URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include, re_path
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
re_path(r'^contracts/', ContractAPIView.as_view(), name="get-contracts-limit"),
|
||||||
|
re_path(r'^contracts-all/', ContractAllAPIView.as_view(), name="get-contracts"),
|
||||||
|
re_path(r'^companies/', CompanyAPIView.as_view(), name="get-companies"),
|
||||||
|
# re_path(r'^events-token/', EventsTokenAPIView.as_view(), name="get-token-events"),
|
||||||
|
|
||||||
|
]
|
||||||
64
contracts/views.py
Normal file
64
contracts/views.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import pytz, random
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
from .serializers import *
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
|
from rest_framework import generics
|
||||||
|
from rest_framework.decorators import authentication_classes, permission_classes
|
||||||
|
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
|
||||||
|
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
# from durin.auth import TokenAuthentication
|
||||||
|
|
||||||
|
# from durin.views import APIAccessTokenView
|
||||||
|
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
from rest_framework import filters
|
||||||
|
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework_api_key.permissions import HasAPIKey
|
||||||
|
|
||||||
|
td = timedelta(hours=7)
|
||||||
|
odt = datetime.now() - td
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
class ContractAPIView(generics.ListAPIView):
|
||||||
|
serializer_class = ContractSerializer
|
||||||
|
queryset = Contract.objects.all()[:25]
|
||||||
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
||||||
|
filterset_fields = ['id',]
|
||||||
|
permission_classes = [HasAPIKey]
|
||||||
|
|
||||||
|
|
||||||
|
class ContractAllAPIView(generics.ListAPIView):
|
||||||
|
serializer_class = ContractSerializer
|
||||||
|
queryset = Contract.objects.all()
|
||||||
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
|
||||||
|
search_fields = ['notice_id', 'original_contract_number', 'title', 'description', 'company__name', 'us_dept', 'us_dept_sub_tier', 'us_office', 'naics_code', 'prod_svc_code']
|
||||||
|
filterset_fields = ['id',]
|
||||||
|
permission_classes = [HasAPIKey]
|
||||||
|
|
||||||
|
|
||||||
|
class CompanyAPIView(generics.ListAPIView):
|
||||||
|
serializer_class = CompanySerializer
|
||||||
|
queryset = Company.objects.all()
|
||||||
|
permission_classes = [HasAPIKey]
|
||||||
|
|
||||||
|
# class PromoAPIView(generics.ListAPIView):
|
||||||
|
# serializer_class = PromoSerializer
|
||||||
|
# queryset = Promo.objects.filter(published=True)
|
||||||
|
# filterset_fields = ['organization__name', 'calendar__shortcode',]
|
||||||
|
# search_fields = ['organization__name', 'calendar__shortcode',]
|
||||||
|
# # permission_classes = [HasAPIKey]
|
||||||
|
|
||||||
|
# def get_queryset(self):
|
||||||
|
# calendar = self.request.GET.get('calendar__shortcode')
|
||||||
|
# queryset = Promo.objects.filter(published=True, calendar__shortcode=calendar).order_by('?')
|
||||||
|
# return queryset
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-06 18:09
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0048_organization_has_map'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='organization',
|
||||||
|
name='city_lnk',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='org_city', to='events.place'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='organization',
|
||||||
|
name='state_lnk',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='org_state', to='events.place'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='organization',
|
||||||
|
name='org_type',
|
||||||
|
field=models.CharField(choices=[('Gv', 'Government'), ('Fb', 'Food & Beverage'), ('Re', 'Retail'), ('Se', 'Service'), ('Vn', 'Venue'), ('Ud', 'Undefined')], default='Re', max_length=31),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='place',
|
||||||
|
name='connection_type',
|
||||||
|
field=models.CharField(choices=[('Pc', 'Precinct'), ('Mu', 'Municipality'), ('Ci', 'City'), ('Co', 'County'), ('Ld', 'Legislative District'), ('St', 'State')], default='Ci', max_length=31),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Official',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=31, unique=True)),
|
||||||
|
('website', models.CharField(blank=True, max_length=31, null=True)),
|
||||||
|
('position', models.CharField(choices=[('Gv', 'Governor'), ('Sc', 'Secretary'), ('Re', 'Representative'), ('Sn', 'Senator'), ('Sr', 'State Rep'), ('Ss', 'State Senator'), ('Cc', 'County Commissioner'), ('Cm', 'Council Member'), ('Ju', 'Judge'), ('Bm', 'Board Member')], default='Ci', max_length=31)),
|
||||||
|
('notes', models.TextField(blank=True, null=True)),
|
||||||
|
('boss', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.place')),
|
||||||
|
('employer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.organization')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-02-18 19:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('events', '0049_organization_city_lnk_organization_state_lnk_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='official',
|
||||||
|
name='bluesky',
|
||||||
|
field=models.CharField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='official',
|
||||||
|
name='email',
|
||||||
|
field=models.CharField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='official',
|
||||||
|
name='instagram',
|
||||||
|
field=models.CharField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='official',
|
||||||
|
name='upscroll',
|
||||||
|
field=models.CharField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='official',
|
||||||
|
name='youtube',
|
||||||
|
field=models.CharField(blank=True, max_length=31, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -80,7 +80,6 @@ class Place(models.Model):
|
|||||||
return u'%s' % self.name
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Official(models.Model):
|
class Official(models.Model):
|
||||||
POSITION_TYPE = (
|
POSITION_TYPE = (
|
||||||
('Gv', 'Governor'),
|
('Gv', 'Governor'),
|
||||||
@@ -96,12 +95,18 @@ class Official(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
name = models.CharField(max_length=31, unique=True)
|
name = models.CharField(max_length=31, unique=True)
|
||||||
website = models.CharField(max_length=31,blank=True, null=True)
|
|
||||||
boss = models.ForeignKey("Place", on_delete=models.CASCADE)
|
boss = models.ForeignKey("Place", on_delete=models.CASCADE)
|
||||||
employer = models.ForeignKey("Organization", on_delete=models.CASCADE)
|
employer = models.ForeignKey("Organization", on_delete=models.CASCADE)
|
||||||
position = models.CharField(max_length=31, choices=POSITION_TYPE, default='Ci')
|
position = models.CharField(max_length=31, choices=POSITION_TYPE, default='Ci')
|
||||||
notes = models.TextField(blank=True, null=True)
|
notes = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
website = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
email = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
bluesky = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
instagram = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
youtube = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
upscroll = models.CharField(max_length=31, blank=True, null=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return "%s" % self.name
|
return "%s" % self.name
|
||||||
|
|
||||||
@@ -135,8 +140,8 @@ class Organization(models.Model):
|
|||||||
barrio = models.CharField(max_length=127, blank=True, null=True)
|
barrio = models.CharField(max_length=127, blank=True, null=True)
|
||||||
city = models.CharField(max_length=127, blank=True, null=True)
|
city = models.CharField(max_length=127, blank=True, null=True)
|
||||||
state = models.CharField(max_length=127, blank=True, null=True)
|
state = models.CharField(max_length=127, blank=True, null=True)
|
||||||
city = models.ForeignKey(Place, on_delete=models.CASCADE, related_name="org_city")
|
city_lnk = models.ForeignKey(Place, on_delete=models.CASCADE, blank=True, null=True, related_name="org_city")
|
||||||
state = models.ForeignKey(Place, on_delete=models.CASCADE, related_name="org_state" )
|
state_lnk = models.ForeignKey(Place, on_delete=models.CASCADE, blank=True, null=True, related_name="org_state" )
|
||||||
zip_code = models.CharField(max_length=15, blank=True, null=True)
|
zip_code = models.CharField(max_length=15, blank=True, null=True)
|
||||||
|
|
||||||
phone_number = models.CharField(max_length=255, blank=True, null=True)
|
phone_number = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|||||||
BIN
media/promo/AtlasObscura.png
Normal file
BIN
media/promo/AtlasObscura.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 402 KiB |
Reference in New Issue
Block a user