Python Django learnings
Moving an app from an extremely outdated code base into Django. Some learnings:
Super quick start into Docker
1pip3 install "cookiecutter>=1.7.0"
2cookiecutter https://github.com/pydanny/cookiecutter-django
"Cookiecutter creates projects from project templates, e.g. Python package projects." Does what it says on the tin. Managed to get a dockerised Django+Python+MSSQL(!?!) running in next to no time.
MSSQL in Django
1curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
2curl https://packages.microsoft.com/config/debian/10/prod.list | tee /etc/apt/sources.list.d/msprod.list
3apt-get update
4ACCEPT_EULA=Y apt-get install -y unixodbc unixodbc-dev mssql-tools g++
5apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
6rm -rf /var/lib/apt/lists/*
7
8cp /opt/microsoft/msodbcsql17/etc/odbcinst.ini /etc/odbcinst.ini
9cat /etc/odbcinst.ini
10pip install pyodbc
11pip install mssql-django
in base.py
1DATABASES = {
2 'default': {
3...
4 'OPTIONS': {
5 'driver': 'ODBC Driver 17 for SQL Server',
6 },
7 },
8}
How to get a Django model file from an existing database
1./manage.py inspectdb > models.py
Gotchas:
- In the latest Django/ Python I've had to add
app_label = '<app-name-in-INSTALLED-APPS>'
for it to use - Not all the tables pulled across had keys. You need one and only one primary key in each table/ view for Django to work. Find the most key like field and add
primary_key=True
to the column metadata
Basic POST handler
in views.py
1from django.core.handlers.wsgi import WSGIRequest
2...
3def <FUNCTNAME>(request: WSGIRequest):
4 if request.method == 'POST':
5 action = request.POST.get('action', 'Search')
Simple way of getting the submitted values.
Creating Excel files
1pip install XlsxWriter
1import io,os
2from django.http import HttpResponse
3import xlsxwriter
4...
5 output = io.BytesIO()
6 workbook = xlsxwriter.Workbook(output)
7 bold_format = workbook.add_format({'bold': True})
8 bold_date_format = workbook.add_format({'bold': True, 'num_format': 'dd/mm/yyyy hh:mm'})
9
10 worksheet = workbook.add_worksheet()
11 worksheet.set_row(0, 65.25)
12 worksheet.insert_image('A1', os.path.dirname(os.path.realpath(__file__)) + '/<IMAGEFILE>')
13 worksheet.write('A2', 'Rundate')
14 worksheet.write('B2', founds[0].datetime.replace(tzinfo=None), bold_date_format)
15 workbook.close()
16 # Rewind the buffer.
17 output.seek(0)
18
19 # Set up the Http response.
20 filename = 'django_simple.xlsx'
21 response = HttpResponse(
22 output,
23 content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
24 )
25 response['Content-Disposition'] = 'attachment; filename=%s' % filename
26
27 return response
More specifics
- XLSXwriter seems to be the Uber-good one if you're not running on Windows. If you are running solely on Windows you can use a COM bridge to get access to all the Excel functionality directly.
- Dates don't work with XLSXwriter if they have timezones. So you have to do that
<FIELD>.replace(tzinfo=NONE)
to use it - Dates come across as numbers, so you then have to ensure the cell you're writing into has the date format you want.
- The
output = io.BytesIO()
captures the output to screen; so once you close the workbook you can then rewind the output and send that raw with the right headers
Filtering result sets
Filtering seems fine
1<MODEL>.objects.extra(
2 select={
3 'NiceNameOne': 'fieldone',
4 'NiceNameTwo': 'fieldtwo'
5 }
6).values(
7 'NiceNameOne',
8 'NiceNameTwo',
9).order_by(
10 'NiceNameOne'
11).distinct(
12)
However I haven't found any way to limit the results in the query itself (e.g. return 20 rows, skipping the first 30). Everything I've read runs the whole query and then does a [30:20]
subset nonsense thing. That doesn't save data query time. Anyone?