winipedia-django 0.2.24__py3-none-any.whl → 0.2.28__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  import django
4
4
  import django_stubs_ext
5
5
  from django.conf import settings
6
- from winipedia_utils.logging.logger import get_logger
6
+ from winipedia_utils.utils.logging.logger import get_logger
7
7
 
8
8
  logger = get_logger(__name__)
9
9
 
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1,4 @@
1
+ """Build script.
2
+
3
+ All subclasses of Builder in the builds package are automatically called.
4
+ """
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1,4 @@
1
+ """Build script.
2
+
3
+ All subclasses of Builder in the builds package are automatically called.
4
+ """
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1,4 @@
1
+ """Configs for winipedia_utils.
2
+
3
+ All subclasses of ConfigFile in the configs package are automatically called.
4
+ """
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -11,7 +11,7 @@ from argparse import ArgumentParser
11
11
  from typing import Any, final
12
12
 
13
13
  from django.core.management import BaseCommand
14
- from winipedia_utils.oop.mixins.mixin import ABCLoggingMixin
14
+ from winipedia_utils.utils.oop.mixins.mixin import ABCLoggingMixin
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
@@ -0,0 +1 @@
1
+ """__init__ module."""
@@ -18,10 +18,10 @@ from django.db.models import (
18
18
  QuerySet,
19
19
  )
20
20
  from django.db.models.deletion import Collector
21
- from winipedia_utils.concurrent.multithreading import multithread_loop
22
- from winipedia_utils.logging.logger import get_logger
21
+ from winipedia_utils.utils.iterating.concurrent.multithreading import multithread_loop
22
+ from winipedia_utils.utils.logging.logger import get_logger
23
23
 
24
- from winipedia_django.database import (
24
+ from winipedia_django.utils.db.models import (
25
25
  hash_model_instance,
26
26
  topological_sort_models,
27
27
  )
@@ -0,0 +1,101 @@
1
+ """Fields module.
2
+
3
+ Utils for working with Django model fields.
4
+ """
5
+
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from django.db.models import Field, Model
9
+
10
+ if TYPE_CHECKING:
11
+ from django.contrib.contenttypes.fields import GenericForeignKey
12
+ from django.db.models.fields.related import ForeignObjectRel
13
+ from django.db.models.options import Options
14
+
15
+
16
+ def get_field_names(
17
+ fields: "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]",
18
+ ) -> list[str]:
19
+ """Get the names of all fields from a Django model including relationships.
20
+
21
+ Retrieves the names of all field objects from a Django model, including
22
+ regular fields, foreign key relationships, reverse foreign key relationships,
23
+ and generic foreign keys. This provides a comprehensive view of all model
24
+ attributes that can be used for introspection, validation, or bulk operations.
25
+
26
+ Args:
27
+ fields (list[Field | ForeignObjectRel | GenericForeignKey]):
28
+ The list of field objects to get names from.
29
+
30
+ Returns:
31
+ list[str]: A list containing the names of all fields.
32
+
33
+ Example:
34
+ >>> from django.contrib.auth.models import User
35
+ >>> fields = get_fields(User)
36
+ >>> field_names = get_field_names(fields)
37
+ >>> 'username' in field_names
38
+ True
39
+ >>> 'email' in field_names
40
+ True
41
+ """
42
+ return [field.name for field in fields]
43
+
44
+
45
+ def get_model_meta(model: type[Model]) -> "Options[Model]":
46
+ """Get the Django model metadata options object.
47
+
48
+ Retrieves the _meta attribute from a Django model class, which contains
49
+ metadata about the model including field definitions, table name, and
50
+ other model configuration options. This is a convenience wrapper around
51
+ accessing the private _meta attribute directly.
52
+
53
+ Args:
54
+ model (type[Model]): The Django model class to get metadata from.
55
+
56
+ Returns:
57
+ Options[Model]: The model's metadata options object containing
58
+ field definitions, table information, and other model configuration.
59
+
60
+ Example:
61
+ >>> from django.contrib.auth.models import User
62
+ >>> meta = get_model_meta(User)
63
+ >>> meta.db_table
64
+ 'auth_user'
65
+ >>> len(meta.get_fields())
66
+ 11
67
+ """
68
+ return model._meta # noqa: SLF001
69
+
70
+
71
+ def get_fields(
72
+ model: type[Model],
73
+ ) -> "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]":
74
+ """Get all fields from a Django model including relationships.
75
+
76
+ Retrieves all field objects from a Django model, including regular fields,
77
+ foreign key relationships, reverse foreign key relationships, and generic
78
+ foreign keys. This provides a comprehensive view of all model attributes
79
+ that can be used for introspection, validation, or bulk operations.
80
+
81
+ Args:
82
+ model (type[Model]): The Django model class to get fields from.
83
+
84
+ Returns:
85
+ list[Field | ForeignObjectRel | GenericForeignKey]: A list
86
+ containing all field objects associated with the model, including:
87
+ - Regular model fields (CharField, IntegerField, etc.)
88
+ - Foreign key fields (ForeignKey, OneToOneField, etc.)
89
+ - Reverse relationship fields (ForeignObjectRel)
90
+ - Generic foreign key fields (GenericForeignKey)
91
+
92
+ Example:
93
+ >>> from django.contrib.auth.models import User
94
+ >>> fields = get_fields(User)
95
+ >>> field_names = [f.name for f in fields if hasattr(f, 'name')]
96
+ >>> 'username' in field_names
97
+ True
98
+ >>> 'email' in field_names
99
+ True
100
+ """
101
+ return get_model_meta(model).get_fields()
@@ -0,0 +1,146 @@
1
+ """Database utilities for Django.
2
+
3
+ This module provides utility functions for working with Django models,
4
+ including hashing, topological sorting, and database operations.
5
+ These utilities help with efficient and safe database interactions.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from graphlib import TopologicalSorter
10
+ from typing import TYPE_CHECKING, Any, Self
11
+
12
+ from django.db.models import DateTimeField, Field, Model
13
+ from django.db.models.fields.related import ForeignKey, ForeignObjectRel
14
+ from django.forms.models import model_to_dict
15
+ from winipedia_utils.utils.logging.logger import get_logger
16
+
17
+ from winipedia_django.utils.db.fields import get_field_names, get_fields
18
+
19
+ if TYPE_CHECKING:
20
+ from django.contrib.contenttypes.fields import GenericForeignKey
21
+ from django.db.models.options import Options
22
+
23
+ logger = get_logger(__name__)
24
+
25
+
26
+ def topological_sort_models(models: list[type[Model]]) -> list[type[Model]]:
27
+ """Sort Django models in dependency order using topological sorting.
28
+
29
+ Analyzes foreign key relationships between Django models and returns them
30
+ in an order where dependencies come before dependents. This ensures that
31
+ when performing operations like bulk creation or deletion, models are
32
+ processed in the correct order to avoid foreign key constraint violations.
33
+
34
+ The function uses Python's graphlib.TopologicalSorter to perform the sorting
35
+ based on ForeignKey relationships between the provided models. Only
36
+ relationships between models in the input list are considered.
37
+
38
+ Args:
39
+ models (list[type[Model]]): A list of Django model classes to sort
40
+ based on their foreign key dependencies.
41
+
42
+ Returns:
43
+ list[type[Model]]: The input models sorted in dependency order, where
44
+ models that are referenced by foreign keys appear before models
45
+ that reference them. Self-referential relationships are ignored.
46
+
47
+ Raises:
48
+ graphlib.CycleError: If there are circular dependencies between models
49
+ that cannot be resolved.
50
+
51
+ Example:
52
+ >>> # Assuming Author model has no dependencies
53
+ >>> # and Book model has ForeignKey to Author
54
+ >>> models = [Book, Author]
55
+ >>> sorted_models = topological_sort_models(models)
56
+ >>> sorted_models
57
+ [<class 'Author'>, <class 'Book'>]
58
+
59
+ Note:
60
+ - Only considers ForeignKey relationships, not other field types
61
+ - Self-referential foreign keys are ignored to avoid self-loops
62
+ - Only relationships between models in the input list are considered
63
+ """
64
+ ts: TopologicalSorter[type[Model]] = TopologicalSorter()
65
+
66
+ for model in models:
67
+ deps = {
68
+ field.related_model
69
+ for field in get_fields(model)
70
+ if isinstance(field, ForeignKey)
71
+ and isinstance(field.related_model, type)
72
+ and field.related_model in models
73
+ and field.related_model is not model
74
+ }
75
+ ts.add(model, *deps)
76
+
77
+ return list(ts.static_order())
78
+
79
+
80
+ def hash_model_instance(
81
+ instance: Model,
82
+ fields: "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]",
83
+ ) -> int:
84
+ """Hash a model instance based on its field values.
85
+
86
+ Generates a hash for a Django model instance by considering the values
87
+ of its fields. This can be useful for comparing instances, especially
88
+ when dealing with related objects or complex data structures. The hash
89
+ is generated by recursively hashing related objects up to a specified
90
+ depth.
91
+ This is not very reliable, use with caution.
92
+ Only use if working with unsafed objects or bulks, as with safed
93
+
94
+ Args:
95
+ instance (Model): The Django model instance to hash
96
+ fields (list[str]): The fields to hash
97
+
98
+ Returns:
99
+ int: The hash value representing the instance's data
100
+
101
+ """
102
+ if instance.pk:
103
+ return hash(instance.pk)
104
+
105
+ field_names = get_field_names(fields)
106
+ model_dict = model_to_dict(instance, fields=field_names)
107
+ sorted_dict = dict(sorted(model_dict.items()))
108
+ values = (type(instance), tuple(sorted_dict.items()))
109
+ return hash(values)
110
+
111
+
112
+ class BaseModel(Model):
113
+ """Base model for all models in the project.
114
+
115
+ Provides common fields and methods for all models.
116
+ """
117
+
118
+ created_at: DateTimeField[datetime, datetime] = DateTimeField(auto_now_add=True)
119
+ updated_at: DateTimeField[datetime, datetime] = DateTimeField(auto_now=True)
120
+
121
+ class Meta:
122
+ """Mark the model as abstract."""
123
+
124
+ # abstract does not inherit in children
125
+ abstract = True
126
+
127
+ def __str__(self) -> str:
128
+ """Base string representation of a model.
129
+
130
+ Returns:
131
+ str: The string representation of the model as all fields and their values.
132
+ """
133
+ fields_values = ", ".join(
134
+ f"{field.name}={getattr(self, field.name)}"
135
+ for field in get_fields(self.__class__)
136
+ )
137
+ return f"{self.__class__.__name__}({fields_values})"
138
+
139
+ def __repr__(self) -> str:
140
+ """Base representation of a model."""
141
+ return str(self)
142
+
143
+ @property
144
+ def meta(self) -> "Options[Self]":
145
+ """Get the meta options for the model."""
146
+ return self._meta
@@ -0,0 +1,60 @@
1
+ """Module for database operations with sql."""
2
+
3
+ from typing import Any
4
+
5
+ from django.db import connection
6
+
7
+
8
+ def execute_sql(
9
+ sql: str, params: dict[str, Any] | None = None
10
+ ) -> tuple[list[str], list[Any]]:
11
+ """Execute raw SQL query and return column names with results.
12
+
13
+ Executes a raw SQL query using Django's database connection and returns
14
+ both the column names and the result rows. This provides a convenient
15
+ way to run custom SQL queries while maintaining Django's database
16
+ connection management and parameter binding for security.
17
+
18
+ The function automatically handles cursor management and ensures proper
19
+ cleanup of database resources. Parameters are safely bound to prevent
20
+ SQL injection attacks.
21
+
22
+ Args:
23
+ sql (str): The SQL query string to execute. Can contain parameter
24
+ placeholders that will be safely bound using the params argument.
25
+ params (dict[str, Any] | None, optional): Dictionary of parameters
26
+ to bind to the SQL query for safe parameter substitution.
27
+ Defaults to None if no parameters are needed.
28
+
29
+ Returns:
30
+ tuple[list[str], list[Any]]: A tuple containing:
31
+ - list[str]: Column names from the query result
32
+ - list[Any]: List of result rows, where each row is a tuple
33
+ of values corresponding to the column names
34
+
35
+ Raises:
36
+ django.db.Error: If there's a database error during query execution
37
+ django.db.ProgrammingError: If the SQL syntax is invalid
38
+ django.db.IntegrityError: If the query violates database constraints
39
+
40
+ Example:
41
+ >>> sql = "SELECT id, username FROM auth_user WHERE is_active = %(active)s"
42
+ >>> params = {"active": True}
43
+ >>> columns, rows = execute_sql(sql, params)
44
+ >>> columns
45
+ ['id', 'username']
46
+ >>> rows[0]
47
+ (1, 'admin')
48
+
49
+ Note:
50
+ - Uses Django's default database connection
51
+ - Automatically manages cursor lifecycle
52
+ - Parameters are safely bound to prevent SQL injection
53
+ - Returns all results in memory - use with caution for large datasets
54
+ """
55
+ with connection.cursor() as cursor:
56
+ cursor.execute(sql=sql, params=params)
57
+ rows = cursor.fetchall()
58
+ column_names = [col[0] for col in cursor.description]
59
+
60
+ return column_names, rows
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: winipedia-django
3
- Version: 0.2.24
3
+ Version: 0.2.28
4
4
  Summary: A utils package for django
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -0,0 +1,23 @@
1
+ winipedia_django/__init__.py,sha256=sY_FUPBGtVwOh4PcoXpa-7h3_2XTgcnKBaPxPYI8ycM,555
2
+ winipedia_django/dev/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
3
+ winipedia_django/dev/artifacts/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
4
+ winipedia_django/dev/artifacts/builder/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
5
+ winipedia_django/dev/artifacts/builder/builder.py,sha256=DdbLRMGQQdPgtYu8DSOZrw8Ukz5EmStSq4etgShh6_I,96
6
+ winipedia_django/dev/artifacts/builds/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
7
+ winipedia_django/dev/artifacts/builds/builder.py,sha256=DdbLRMGQQdPgtYu8DSOZrw8Ukz5EmStSq4etgShh6_I,96
8
+ winipedia_django/dev/configs/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
9
+ winipedia_django/dev/configs/configs.py,sha256=FF25IOrj2wBPdybdr8-txGYKRBbS7hMWUVX68PyIKGo,115
10
+ winipedia_django/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ winipedia_django/utils/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
12
+ winipedia_django/utils/commands/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
13
+ winipedia_django/utils/commands/base/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
14
+ winipedia_django/utils/commands/base/command.py,sha256=JKRiNSLG2OaNsYNIQptXLvnLryo96kNEr4DfoVo2I6g,13467
15
+ winipedia_django/utils/db/__init__.py,sha256=XHsbmjiaGom-KX-S3leCY9cJD3aP9p_0X6xYMcdkHBU,23
16
+ winipedia_django/utils/db/bulk.py,sha256=Ak08n5bKoa_OKYblBCjSq69MRM6sMIqxbUCOkHZpQJY,19906
17
+ winipedia_django/utils/db/fields.py,sha256=_jQotlkUdv7WNh-o0Dzmch2q28jbJUOhNDSIBlIvZTk,3600
18
+ winipedia_django/utils/db/models.py,sha256=c-kprUqXkqA0AcoARffGXwBAbMXo7mi9G-YTSC3-r94,5203
19
+ winipedia_django/utils/db/sql.py,sha256=0vyGfyek-9cYW-MidD_LSo1c7hYdhier4IonjMv9HNo,2346
20
+ winipedia_django-0.2.28.dist-info/METADATA,sha256=x9FEH_5dFsMfZcaWhrRAA4OadfK9Isx7im_D2SUQHQo,19942
21
+ winipedia_django-0.2.28.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
22
+ winipedia_django-0.2.28.dist-info/licenses/LICENSE,sha256=o316mE2gGzd__JT69p7S_zlOmKiHh8YjpImCCcWyTvM,1066
23
+ winipedia_django-0.2.28.dist-info/RECORD,,
@@ -1,288 +0,0 @@
1
- """Database utilities for Django.
2
-
3
- This module provides utility functions for working with Django models,
4
- including hashing, topological sorting, and database operations.
5
- These utilities help with efficient and safe database interactions.
6
- """
7
-
8
- from datetime import datetime
9
- from graphlib import TopologicalSorter
10
- from typing import TYPE_CHECKING, Any, Self
11
-
12
- from django.db import connection
13
- from django.db.models import DateTimeField, Field, Model
14
- from django.db.models.fields.related import ForeignKey, ForeignObjectRel
15
- from django.forms.models import model_to_dict
16
- from winipedia_utils.logging.logger import get_logger
17
-
18
- if TYPE_CHECKING:
19
- from django.contrib.contenttypes.fields import GenericForeignKey
20
- from django.db.models.options import Options
21
-
22
- logger = get_logger(__name__)
23
-
24
-
25
- def get_model_meta(model: type[Model]) -> "Options[Model]":
26
- """Get the Django model metadata options object.
27
-
28
- Retrieves the _meta attribute from a Django model class, which contains
29
- metadata about the model including field definitions, table name, and
30
- other model configuration options. This is a convenience wrapper around
31
- accessing the private _meta attribute directly.
32
-
33
- Args:
34
- model (type[Model]): The Django model class to get metadata from.
35
-
36
- Returns:
37
- Options[Model]: The model's metadata options object containing
38
- field definitions, table information, and other model configuration.
39
-
40
- Example:
41
- >>> from django.contrib.auth.models import User
42
- >>> meta = get_model_meta(User)
43
- >>> meta.db_table
44
- 'auth_user'
45
- >>> len(meta.get_fields())
46
- 11
47
- """
48
- return model._meta # noqa: SLF001
49
-
50
-
51
- def get_fields(
52
- model: type[Model],
53
- ) -> "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]":
54
- """Get all fields from a Django model including relationships.
55
-
56
- Retrieves all field objects from a Django model, including regular fields,
57
- foreign key relationships, reverse foreign key relationships, and generic
58
- foreign keys. This provides a comprehensive view of all model attributes
59
- that can be used for introspection, validation, or bulk operations.
60
-
61
- Args:
62
- model (type[Model]): The Django model class to get fields from.
63
-
64
- Returns:
65
- list[Field | ForeignObjectRel | GenericForeignKey]: A list
66
- containing all field objects associated with the model, including:
67
- - Regular model fields (CharField, IntegerField, etc.)
68
- - Foreign key fields (ForeignKey, OneToOneField, etc.)
69
- - Reverse relationship fields (ForeignObjectRel)
70
- - Generic foreign key fields (GenericForeignKey)
71
-
72
- Example:
73
- >>> from django.contrib.auth.models import User
74
- >>> fields = get_fields(User)
75
- >>> field_names = [f.name for f in fields if hasattr(f, 'name')]
76
- >>> 'username' in field_names
77
- True
78
- >>> 'email' in field_names
79
- True
80
- """
81
- return get_model_meta(model).get_fields()
82
-
83
-
84
- def get_field_names(
85
- fields: "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]",
86
- ) -> list[str]:
87
- """Get the names of all fields from a Django model including relationships.
88
-
89
- Retrieves the names of all field objects from a Django model, including
90
- regular fields, foreign key relationships, reverse foreign key relationships,
91
- and generic foreign keys. This provides a comprehensive view of all model
92
- attributes that can be used for introspection, validation, or bulk operations.
93
-
94
- Args:
95
- fields (list[Field | ForeignObjectRel | GenericForeignKey]):
96
- The list of field objects to get names from.
97
-
98
- Returns:
99
- list[str]: A list containing the names of all fields.
100
-
101
- Example:
102
- >>> from django.contrib.auth.models import User
103
- >>> fields = get_fields(User)
104
- >>> field_names = get_field_names(fields)
105
- >>> 'username' in field_names
106
- True
107
- >>> 'email' in field_names
108
- True
109
- """
110
- return [field.name for field in fields]
111
-
112
-
113
- def topological_sort_models(models: list[type[Model]]) -> list[type[Model]]:
114
- """Sort Django models in dependency order using topological sorting.
115
-
116
- Analyzes foreign key relationships between Django models and returns them
117
- in an order where dependencies come before dependents. This ensures that
118
- when performing operations like bulk creation or deletion, models are
119
- processed in the correct order to avoid foreign key constraint violations.
120
-
121
- The function uses Python's graphlib.TopologicalSorter to perform the sorting
122
- based on ForeignKey relationships between the provided models. Only
123
- relationships between models in the input list are considered.
124
-
125
- Args:
126
- models (list[type[Model]]): A list of Django model classes to sort
127
- based on their foreign key dependencies.
128
-
129
- Returns:
130
- list[type[Model]]: The input models sorted in dependency order, where
131
- models that are referenced by foreign keys appear before models
132
- that reference them. Self-referential relationships are ignored.
133
-
134
- Raises:
135
- graphlib.CycleError: If there are circular dependencies between models
136
- that cannot be resolved.
137
-
138
- Example:
139
- >>> # Assuming Author model has no dependencies
140
- >>> # and Book model has ForeignKey to Author
141
- >>> models = [Book, Author]
142
- >>> sorted_models = topological_sort_models(models)
143
- >>> sorted_models
144
- [<class 'Author'>, <class 'Book'>]
145
-
146
- Note:
147
- - Only considers ForeignKey relationships, not other field types
148
- - Self-referential foreign keys are ignored to avoid self-loops
149
- - Only relationships between models in the input list are considered
150
- """
151
- ts: TopologicalSorter[type[Model]] = TopologicalSorter()
152
-
153
- for model in models:
154
- deps = {
155
- field.related_model
156
- for field in get_fields(model)
157
- if isinstance(field, ForeignKey)
158
- and isinstance(field.related_model, type)
159
- and field.related_model in models
160
- and field.related_model is not model
161
- }
162
- ts.add(model, *deps)
163
-
164
- return list(ts.static_order())
165
-
166
-
167
- def execute_sql(
168
- sql: str, params: dict[str, Any] | None = None
169
- ) -> tuple[list[str], list[Any]]:
170
- """Execute raw SQL query and return column names with results.
171
-
172
- Executes a raw SQL query using Django's database connection and returns
173
- both the column names and the result rows. This provides a convenient
174
- way to run custom SQL queries while maintaining Django's database
175
- connection management and parameter binding for security.
176
-
177
- The function automatically handles cursor management and ensures proper
178
- cleanup of database resources. Parameters are safely bound to prevent
179
- SQL injection attacks.
180
-
181
- Args:
182
- sql (str): The SQL query string to execute. Can contain parameter
183
- placeholders that will be safely bound using the params argument.
184
- params (dict[str, Any] | None, optional): Dictionary of parameters
185
- to bind to the SQL query for safe parameter substitution.
186
- Defaults to None if no parameters are needed.
187
-
188
- Returns:
189
- tuple[list[str], list[Any]]: A tuple containing:
190
- - list[str]: Column names from the query result
191
- - list[Any]: List of result rows, where each row is a tuple
192
- of values corresponding to the column names
193
-
194
- Raises:
195
- django.db.Error: If there's a database error during query execution
196
- django.db.ProgrammingError: If the SQL syntax is invalid
197
- django.db.IntegrityError: If the query violates database constraints
198
-
199
- Example:
200
- >>> sql = "SELECT id, username FROM auth_user WHERE is_active = %(active)s"
201
- >>> params = {"active": True}
202
- >>> columns, rows = execute_sql(sql, params)
203
- >>> columns
204
- ['id', 'username']
205
- >>> rows[0]
206
- (1, 'admin')
207
-
208
- Note:
209
- - Uses Django's default database connection
210
- - Automatically manages cursor lifecycle
211
- - Parameters are safely bound to prevent SQL injection
212
- - Returns all results in memory - use with caution for large datasets
213
- """
214
- with connection.cursor() as cursor:
215
- cursor.execute(sql=sql, params=params)
216
- rows = cursor.fetchall()
217
- column_names = [col[0] for col in cursor.description]
218
-
219
- return column_names, rows
220
-
221
-
222
- def hash_model_instance(
223
- instance: Model,
224
- fields: "list[Field[Any, Any] | ForeignObjectRel | GenericForeignKey]",
225
- ) -> int:
226
- """Hash a model instance based on its field values.
227
-
228
- Generates a hash for a Django model instance by considering the values
229
- of its fields. This can be useful for comparing instances, especially
230
- when dealing with related objects or complex data structures. The hash
231
- is generated by recursively hashing related objects up to a specified
232
- depth.
233
- This is not very reliable, use with caution.
234
- Only use if working with unsafed objects or bulks, as with safed
235
-
236
- Args:
237
- instance (Model): The Django model instance to hash
238
- fields (list[str]): The fields to hash
239
-
240
- Returns:
241
- int: The hash value representing the instance's data
242
-
243
- """
244
- if instance.pk:
245
- return hash(instance.pk)
246
-
247
- field_names = get_field_names(fields)
248
- model_dict = model_to_dict(instance, fields=field_names)
249
- sorted_dict = dict(sorted(model_dict.items()))
250
- values = (type(instance), tuple(sorted_dict.items()))
251
- return hash(values)
252
-
253
-
254
- class BaseModel(Model):
255
- """Base model for all models in the project.
256
-
257
- Provides common fields and methods for all models.
258
- """
259
-
260
- created_at: DateTimeField[datetime, datetime] = DateTimeField(auto_now_add=True)
261
- updated_at: DateTimeField[datetime, datetime] = DateTimeField(auto_now=True)
262
-
263
- class Meta:
264
- """Mark the model as abstract."""
265
-
266
- # abstract does not inherit in children
267
- abstract = True
268
-
269
- def __str__(self) -> str:
270
- """Base string representation of a model.
271
-
272
- Returns:
273
- str: The string representation of the model as all fields and their values.
274
- """
275
- fields_values = ", ".join(
276
- f"{field.name}={getattr(self, field.name)}"
277
- for field in get_fields(self.__class__)
278
- )
279
- return f"{self.__class__.__name__}({fields_values})"
280
-
281
- def __repr__(self) -> str:
282
- """Base representation of a model."""
283
- return str(self)
284
-
285
- @property
286
- def meta(self) -> "Options[Self]":
287
- """Get the meta options for the model."""
288
- return self._meta
@@ -1,9 +0,0 @@
1
- winipedia_django/__init__.py,sha256=dl3DvZ1AJSkQDEnMSdYMbrnQs6Jmofq4c_SkOG3MoVA,549
2
- winipedia_django/bulk.py,sha256=PmGJE6g1S7_fqqWOWRGV9uExwMcexb5SeR0Hj0k46z0,19877
3
- winipedia_django/command.py,sha256=WS9kO_0uvimH7fnxy5GJZp0mREViPPoodBT_4l8DCzM,13461
4
- winipedia_django/database.py,sha256=fvjLy0hrR5SEgJ9inGB2tbXblipvpMhX84tS3yjrdEs,10646
5
- winipedia_django/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- winipedia_django-0.2.24.dist-info/METADATA,sha256=-bFqnHoM8UjC7elQdPzIU0SMCTZyhSQAbSFAYV_fTI8,19942
7
- winipedia_django-0.2.24.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
8
- winipedia_django-0.2.24.dist-info/licenses/LICENSE,sha256=o316mE2gGzd__JT69p7S_zlOmKiHh8YjpImCCcWyTvM,1066
9
- winipedia_django-0.2.24.dist-info/RECORD,,