-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add supporting functions - Add basic User model
- Loading branch information
Showing
3 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
""" | ||
This is a simple minimal setup for using Django ORMs. | ||
Import this when creating models and then the models can be used as normal. | ||
""" | ||
|
||
import os | ||
|
||
import django | ||
from django.conf import settings | ||
|
||
from twfy_tools.common.config import config | ||
|
||
# Allow use in notebooks | ||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" | ||
|
||
if not settings.configured: | ||
settings.configure( | ||
DEBUG=True, | ||
SECRET_KEY="your-secret-key", | ||
ALLOWED_HOSTS=["*"], | ||
INSTALLED_APPS=[ | ||
"twfy_tools", | ||
], | ||
DATABASES={ | ||
"default": { | ||
"ENGINE": "django.db.backends.mysql", | ||
"NAME": config.TWFY_DB_NAME, | ||
"USER": config.TWFY_DB_USER, | ||
"PASSWORD": config.TWFY_DB_PASS, | ||
"HOST": config.TWFY_DB_HOST, | ||
"PORT": config.TWFY_DB_PORT, | ||
} | ||
}, | ||
) | ||
|
||
django.setup() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from typing import Any, Callable, TypeVar | ||
|
||
from django.db import models | ||
|
||
from typing_extensions import ParamSpec, dataclass_transform | ||
|
||
FieldType = TypeVar( | ||
"FieldType", | ||
bound=models.Field, | ||
) | ||
P = ParamSpec("P") | ||
|
||
|
||
def field( | ||
model_class: Callable[P, FieldType], | ||
null: bool = False, | ||
*args: P.args, | ||
**kwargs: P.kwargs, | ||
) -> Any: | ||
""" | ||
Helper function for basic field creation. | ||
So the type checker doesn't complain about the return type | ||
and you can specify the specify type of the item as a typehint. | ||
""" | ||
if args: | ||
raise ValueError("Positional arguments are not supported") | ||
kwargs["null"] = null | ||
if isinstance(model_class, type) and issubclass(model_class, models.Field): | ||
return model_class(**kwargs) | ||
else: | ||
raise ValueError(f"Invalid model class {model_class}") | ||
|
||
|
||
@dataclass_transform(kw_only_default=True, field_specifiers=(field,)) | ||
class DataclassModelBase(models.base.ModelBase): | ||
def __new__(cls, name: str, bases: tuple[type], dct: dict[str, Any], **kwargs: Any): | ||
""" | ||
Basic metaclass to make class keyword parameters into a Meta class. | ||
""" | ||
if kwargs: | ||
dct["Meta"] = type("Meta", (dct.get("Meta", type),), kwargs) | ||
return super().__new__(cls, name, bases, dct) | ||
|
||
|
||
class DataclassModel(models.Model, metaclass=DataclassModelBase): | ||
""" | ||
Basic wrapper that adds tidier metaclass config, and dataclass | ||
prompting. | ||
""" | ||
|
||
|
||
class UnManagedDataclassModel(DataclassModel, managed=False): ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
""" | ||
This is a simple one file setup for using django's ORM models. | ||
""" | ||
|
||
import datetime | ||
from enum import IntEnum | ||
from typing import Optional | ||
|
||
from django.db import models | ||
|
||
from twfy_tools.db import django_setup as django_setup | ||
|
||
from ..common.enum_backport import StrEnum | ||
from .model_helper import UnManagedDataclassModel, field | ||
|
||
datetime_min = datetime.datetime(1, 1, 1, 0, 0, 0) | ||
|
||
|
||
class UserLevels(StrEnum): | ||
VIEWER = "Viewer" | ||
USER = "User" | ||
MODERATOR = "Moderator" | ||
ADMINISTRATOR = "Administrator" | ||
SUPERUSER = "Superuser" | ||
|
||
|
||
class OptinValues(IntEnum): | ||
OPTIN_SERVICE = 1 | ||
OPTIN_STREAM = 2 | ||
OPTIN_ORG = 4 | ||
|
||
|
||
class User(UnManagedDataclassModel, db_table="users"): | ||
user_id: Optional[int] = field(models.AutoField, primary_key=True) | ||
firstname: str = field(models.CharField, max_length=255, default="") | ||
lastname: str = field(models.CharField, max_length=255, default="") | ||
email: str = field(models.CharField, max_length=255) | ||
password: str = field(models.CharField, max_length=102, default="") | ||
lastvisit: datetime.datetime = field(models.DateTimeField, default=datetime_min) | ||
registrationtime: datetime.datetime = field( | ||
models.DateTimeField, default=datetime_min | ||
) | ||
registrationip: str = field(models.CharField, max_length=20, blank=True, null=True) | ||
status: UserLevels = field( | ||
models.CharField, | ||
max_length=13, | ||
blank=True, | ||
null=True, | ||
default=UserLevels.VIEWER, | ||
) | ||
emailpublic: int = field(models.IntegerField, default=0) | ||
optin: int = field(models.IntegerField, default=0) | ||
deleted: int = field(models.IntegerField, default=0) | ||
postcode: str = field(models.CharField, max_length=10, blank=True, null=True) | ||
registrationtoken: str = field(models.CharField, max_length=24, default="") | ||
confirmed: int = field(models.IntegerField, default=0) | ||
url: str = field(models.CharField, max_length=255, blank=True, null=True) | ||
api_key: str = field( | ||
models.CharField, unique=True, max_length=24, blank=True, null=True | ||
) | ||
facebook_id: str = field(models.CharField, max_length=24, blank=True, null=True) | ||
facebook_token: str = field(models.CharField, max_length=200, blank=True, null=True) | ||
|
||
UserLevels = UserLevels | ||
OptinValues = OptinValues | ||
|
||
def __str__(self): | ||
return f"{self.status}: {self.email}" | ||
|
||
def get_optin_values(self) -> list[OptinValues]: | ||
""" | ||
Returns a list of OptinValues that match the user's optin value. | ||
""" | ||
matched_values: list[OptinValues] = [] | ||
for value in OptinValues: | ||
if self.optin & value: | ||
matched_values.append(value) | ||
return matched_values | ||
|
||
def add_optin(self, optin_value: OptinValues): | ||
""" | ||
Add an optin value to the user. | ||
""" | ||
self.optin |= optin_value | ||
|
||
def remove_optin(self, optin_value: OptinValues): | ||
""" | ||
Remove an optin value from the user. | ||
""" | ||
self.optin &= ~optin_value |