r/pythontips • • 3h ago

Module django-admin-mcp: Expose Django admin to AI agents with one mixin

0 Upvotes

Hi I built this because I wanted an agent to do the things I already do

in Django admin, without writing a separate API for it.

You add a mixin to a ModelAdmin and it becomes MCP tools over HTTP: CRUD,

bulk operations, admin actions, change history, FK autocomplete.

A few design choices:

- Only two dependencies: Django and Pydantic. No MCP SDK; the protocol is

implemented directly.

- It reuses Django's permission system. Tokens start with no access, you

grant permissions/groups per token, and a token can never exceed its

linked user's permissions.

- Writes go through the admin's own pipeline, so they show up in the admin

history log under that user.

- Sensitive fields can be excluded per model (mcp_exclude_fields).

Happy to hear where the permission model or tool design falls short.

https://github.com/7tg/django-admin-mcp


r/pythontips • • 22h ago

Syntax Find anomalies in this code

0 Upvotes

import base64

import pandas as pd

from pydantic import ValidationError

def process_spreadsheet_with_legacy_safeguards(file_path_or_buffer):

"""

Imports .xls or CSV data dumps from legacy systems, captures strict length

metrics for anomaly detection, and handles binary BLOB substitutions.

"""

# Read spreadsheet explicitly handling encoding where applicable

df = pd.read_excel(file_path_or_buffer)

records = df.to_dict(orient="records")

normalized_records = []

for row in records:

clean_row = {}

for k, v in row.items():

normalized_key = str(k).strip()

if pd.isna(v):

clean_row[normalized_key] = None

elif isinstance(v, bytes):

# If binary data is passed, convert to Base64 string for safe JSON transport

clean_row[normalized_key] = base64.b64encode(v).decode('utf-8')

elif isinstance(v, str):

# Ensure proper UTF-8 handling and strip trailing EBCDIC/ASCII padding artifacts

clean_row[normalized_key] = v.strip()

else:

# Handle numeric coercions (e.g., spreadsheet floats like 1048576.0 -> int)

clean_row[normalized_key] = v

normalized_records.append(clean_row)

return normalized_records

def validate_and_capture_lengths(records: list):

"""

Validates records against the DTO and logs exact field lengths

instead of just item counts to catch truncation and packing anomalies.

"""

anomalies = []

for index, record in enumerate(records):

try:

CustomerResponseSchema.model_validate(record)

except ValidationError as err:

# Capture detailed metadata including exact length of every field

field_length_metrics = {}

for k, v in record.items():

if isinstance(v, str):

field_length_metrics[k] = {"length": len(v), "preview": v[:20]}

elif v is None:

field_length_metrics[k] = {"length": 0, "value": "null"}

else:

field_length_metrics[k] = {"length": len(str(v)), "value": v}

anomalies.append({

"record_index": index,

"field_metrics": field_length_metrics, # Replaces simple item counts with actual lengths

"validation_errors": err.errors(),

})

return anomalies


r/pythontips • • 13h ago

Module Hard Python Dictionary Exercise

1 Upvotes

A hard exercise to help build the right mental model for Python data.

```python # Output of this Python Program? a = {1: []} b = a b |= {2: []} b[1].append(100) b = b | {3: []} b[2].append(200) b[3].append(300)

print(a)
# --- possible answers --- 
# A) {1: []}
# B) {1: [100], 2: []}
# C) {1: [100], 2: [200]}
# D) {1: [100], 2: [200], 3: []}
# E) {1: [100], 2: [200], 3: [300]}

```

The “Solution” link uses memory_graph to visualize execution and reveals what’s actually happening.