Django Unleashed Framework
1.46K subscribers
2.17K photos
2.58K links
Лучшие материалы по разработке на фреймворке Django на русском и английском языке

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/media
Download Telegram
How to integrate stripe to Django

Step 1: Install the required packages
Ensure that you have the necessary packages installed. You can use pip to install them:
pip install stripe
pip install djstripe

Step 2: Configure Django settings
Open your Django project's settings file (setting...

Read: https://ifiokambrose.hashnode.dev/how-to-integrate-stripe-to-django
Road-Map for Python Developers

Should I learn Python? Some weeks ago, someone asked me if Python is good for beginners.
I ponder the questions above and figured many people still have no idea what programming language to use.
The fact that new evolving languages constantly bomba...

Read: https://learnhubafrica.hashnode.dev/road-map-for-python-developers
DJANGO-sign in page with OTP verification via email

While learning a framework ,creating mini projects helps us to explore the features of the framework.Now,we are going to create a simple sign-in page with email verification using Django.At the end of this blog,you will get an insight about the djang...

Read: https://pythongeek.hashnode.dev/django-sign-in-page-with-otp-verification-via-email
👍1
Django-Dynamic HTML page creation with image(user profile page )

In this blog,we are going to create a log-in page for our page and we will create a dynamic html page for displaying user’s profile and personal details whoever logs in.Displaying user uploaded images inside an app along with user details is explaine...

Read: https://pythongeek.hashnode.dev/django-dynamic-html-page-creation-with-imageuser-profile-page
Creating Open-Source Resources for The Community (Ep 2)

Mastori, as the name implies, is a platform where community members can share their blogs and articles. The name "Mastori" originates from Kenyan slang, sheng, meaning "many stories." Our vision is to provide a space for individuals to write about to...

Read: https://spaceyatech.hashnode.dev/creating-open-source-resources-for-the-community-ep-2
Mastering Django CI/CD using GitHub Actions

Testing and delivery is a common repetitive cycle in application development. This cycle consumes more time and resources as we fix or add more features to our application. Automating this repetitive process will reduce the time spent in application ...

Read: https://thecodeway.hashnode.dev/mastering-django-cicd-using-github-actions
Django Unleashed Framework
Photo
Интеграция Django с материализованными представлениями PostgreSQL

Django  —  один из самых популярных веб-фреймворков, написанных на Python. Он следует принципу “Не повторяйся” (DRY) и быстро решает задачи веб-разработки с помощью набора инструментов, библиотек и соглашений.

Действительно продвинутым Django делает встроенная поддержка ORM (механизма объектно-реляционного отображения), который разрабатывает команда Django. Модель данных в Django представлена в виде классов Python, в которых можно создавать и запрашивать таблицы базы данных без использования необработанных SQL-запросов.

В этой статье мы рассмотрим, как интегрировать Django с материализованными представлениями PostgreSQL. Настроим ORM Django на полную поддержку материализованных представлений, определив модели материализованных представлений в проекте Django таким образом, чтобы изменения модели могли быть обнаружены системой миграции Django.

Что такое материализованные представления?

Представления в движках баз данных  —  это виртуальные таблицы, предоставляющие возможность выполнять запросы и получать данные из существующих таблиц. Они позволяют упростить процесс выполнения сложных запросов. Однако использование представлений, динамически выполняющих первичный запрос (primary query) при каждом обращении, может идти в ущерб производительности.

Именно здесь в игру вступают материализованные представления. В отличие от обычных, материализованные представления хранят результаты базового запроса в физической таблице. Другими словами, материализованные представления компилируют результаты запроса и сохраняют их как отдельную сущность в базе данных. Поэтому получить доступ к материализованным представлениям можно намного быстрее, чем к обычным представлениям, предполагающим повторное выполнение запроса при каждом обращении.

При этом необходимо учитывать некоторые недостатки материализованных представлений.

1. Данные в материализованных представлениях могут устаревать, если не обновлять их регулярно, что может привести к несоответствиям.
2. Необходимо учитывать требования к хранению, поскольку материализованные представления потребляют дисковое пространство для хранения данных.
3. Материализованные представления добавляют сложности системе, так как требуют обслуживания при обновлении базовых таблиц.

Создание материализованного представления в PostgreSQL

Материализованное представление можно создать с помощью следующей команды SQL:
CREATE MATERIALIZED VIEW popular_posts AS
SELECT * FROM posts WHERE rating > 200;
Этот запрос создаст новое материализованное представление из базового запроса с кэшированным результатом. При этом обновленные данные в исходной таблице не будут автоматически доступны в материализованном представлении, так как их нужно будет обновить вручную с помощью следующей команды:
REFRESH MATERIALIZED VIEW popular_posts;
Эта команда обновит материализованное представление и заполнит свежими данными базовую таблицу, а также перекомпилирует определение базового запроса материализованного представления.

Проблема

Поскольку в настоящее время ORM Django поддерживает только таблицы баз данных, мне стало интересно, можно ли настроить ORM Django для поддержки материализованных представлений. Проведя исследование, я понял, что можно добиться этого несколькими способами, но не был удовлетворен ни одним решением, так как ни одна из настроек не могла полностью поддерживать материализованные представления для использования в качестве моделей Django.

Одно из решений предполагало создание пустого файла миграции вручную и указание SQL-запроса для создания материализованного представления с помощью команды RunSQL.
from django.db import migrations

class Migration(migrations.Migration):

dependencies = [
("api", "0001_initial"),
]

operations = [
migrations.RunSQL(
sql="CREATE MATERIALIZED VIEW popular_posts AS SELECT * FROM posts WHERE rating > 200",
reverse_sql="DROP MATERIALIZED VIEW popular_posts"
)
]

Кроме того, нео[...]
1
Django Unleashed Framework
Интеграция Django с материализованными представлениями PostgreSQL Django  —  один из самых популярных веб-фреймворков, написанных на Python. Он следует принципу “Не повторяйся” (DRY) и быстро решает задачи веб-разработки с помощью набора инструментов, библиотек…
бходимо создать класс модели, определив поля точно так же, как и в запросе материализованного представления. Класс модели должен иметь:

* опцию managed, которую нужно установить в false в определении мета-класса для указания того, что схема базы данных не должна управляться Django, чтобы предотвратить создание новой таблицы системой миграции;
* опцию db_table, которая должна быть явно установлена в соответствии с именем материализованного представления.
class PopularPosts(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
tag_names = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
rating = models.PositiveIntegerField()

class Meta:
managed = False
db_table = 'popular_posts'
На мой взгляд, данный подход не является оптимальным решением, эффективным в долгосрочной перспективе, особенно при частых обновлениях или изменениях атрибутов класса модели. Когда потребуется изменение атрибутов класса модели, нужно переписывать новый необработанный запрос в новом файле миграции, что может занять много времени и чревато ошибками. Более того, это может стать громоздкой задачей, особенно по мере роста и развития приложения с течением времени.

Как интегрировать Django с материализованными представлениями

Чтобы интегрировать Django с материализованными представлениями, в нашем примере будет применено несколько настроек.

* Создание пользовательского класса модели.
* Создание пользовательского класса поля модели.
* Создание пользовательского движка базы данных для PostgreSQL.
* Соединение всего созданного в проекте.

Шаг 1. Создание пользовательского класса модели

Первым шагом к интеграции Django с материализованными представлениями в PostgreSQL является создание пользовательского класса модели с целью сообщить Django, что модель предназначена для материализованного представления.

Существует несколько способов определить, является ли класс модели материализованным представлением. Я создал класс модели таким образом, чтобы он принимал два пользовательских атрибута класса Meta внутри класса модели.

* materialized_viewуказывает, что класс модели является материализованным представлением, а не таблицей.
* view_parent_modelуказывает классу модели, какой реальный класс модели должен использоваться, чтобы создать базовый запрос для материализованного представления.
class MaterializedViewModel(models.Model):

class Meta:
materialized_view = True
view_parent_model = 'app_label.Model'
Обычно Django не позволяет определять пользовательские атрибуты своего класса Meta внутри классов модели, выдавая исключение TypeError:
raise TypeError(
TypeError: 'class Meta' got invalid attribute(s): materialized_view
Проведя исследование, я обнаружил, что в Django можно использовать только атрибуты Meta, которые статически определены в кортеже DEFAULT_NAMES, который находится в модуле django.db.models.options. Чтобы устранить это ограничение, я применил обходной путь, импортировав модуль options и переопределив переменную DEFAULT_NAMESв файле __init__.pyмодуля проекта перед наполнением приложений Django. Эта модификация обеспечивает поддержку пользовательских атрибутов в классе Meta.
# djangoProject/__init__.py

import django.db.models.options as options

options.DEFAULT_NAMES += ('materialized_view', 'view_parent_model',)
Шаг 2. Создание пользовательского поля модели

Следующий шаг  —  создание пользовательского поля модели, специально предназначенного для класса модели материализованного представления, которое будет иметь два пользовательских атрибута. Каждое из пользовательских полей, указанных в классе модели, впоследствии будет преобразовано в необработанные SQL-запросы для генерации SQL, что необходимо для создания материализованного представления.
from[...]
Django Unleashed Framework
бходимо создать класс модели, определив поля точно так же, как и в запросе материализованного представления. Класс модели должен иметь: * опцию managed, которую нужно установить в false в определении мета-класса для указания того, что схема базы данных не…
django.db.models import fields
from django.db.models.expressions import Combinable, ExpressionWrapper, F

class MaterializedViewField(fields.Field):
def __init__(self, child, source=None, **kwargs):
super().__init__(**kwargs)
self.child = child

if isinstance(source, Combinable) or source is None:
self.source = source

elif isinstance(source, str):
self.source = ExpressionWrapper(F(source), output_field=child)

else:
self.source = None

def deconstruct(self):

"""
Переопределение метода deconstruct для включения атрибутов пользовательских полей в файлы миграции
при выполнении команды `makemigrations` в отншении модели материализованного представления.

"""

name, path, args, keywords = super().deconstruct()

keywords.update(
source=self.source, child=self.child
)
return name, path, args, keywords
Шаг 3. Создание пользовательского движка базы данных для PostgreSQL

Следующий шаг  —  создание пользовательского движка базы данных с пользовательским классом редактора. Этот движок отвечает за реализацию необходимой настройки схемы.

Чтобы настроить редактор схем баз данных Django, нужно определить новый движок базы данных в проекте и сослаться на него в атрибуте ENGINEзаписи DATABASESв файле настроек проекта.

Обратите внимание: пользовательский движок базы данных нужно поместить в каталог с файлом base.pyи классом DatabaseWrapper.

За дополнительной информацией обратитесь к документации Django.

Ниже приведен пример структуры папок, где движок базы данных помещен в приложение Django под названием core и в подпапку backends.
project_root/
...
django_project/
__init__.py
settings.py

core/
__init__.py
backends/
__init__.py
db/
__init__.py
base.py
Следующий код является примером пользовательского движка базы данных (он расположен в файле base.py).
from django.apps import apps
from django.db.backends.postgresql import base
from django.db.models import QuerySet, options, Model

from api.fields import MaterializedViewField

class DatabaseSchemaEditor(base.DatabaseSchemaEditor):
sql_create_materialized_view = "CREATE MATERIALIZED VIEW %(table)s AS %(definition)s"
sql_delete_materialized_view = "DROP MATERIALIZED VIEW %(table)s"
sql_refresh_materialized_View = "REFRESH MATERIALIZED VIEW %(concurrently)s %(view)s"

@staticmethod
def model_meta(model: type[Model]) -> options.Options:
return model._meta

def _get_parent_model(self, model: type[Model]):
"""
Возвращает базовую модель представления, которая будет использоваться для генерации SQL материализованного представления.
"""
parent_model = getattr(self.model_meta(model), 'view_parent_model', None)

if parent_model:
return apps.get_model(*parent_model.split('.'))

def model_is_materialized_view(self, model: type[Model]) -> bool:
"""Проверяет, является ли класс модели моделью материализованного представления или обычной моделью django."""
return getattr(self.model_meta(model), 'materialized_view', False)

def get_queryset(self, model: Model, extra_field=None):
"""Генерирует набор запросов из предоставленной родительской модели и предоставленных полей."""

def append_field(_model_field):

if _model_field.source is None:
concrete_fields.append(_model_field.name)
else:
annotation_fields.update({_model_field.attname: _model_field.source})

concrete_fields = []
annotation_fields = dict()

for field_name, field in model.__dict__.items():
if hasattr(field, 'field'):
model_field: MaterializedViewField = field.field

if isinstance(model_field, MaterializedViewField):
append_field(model_field)

if extra_field:
append_field(extra_field)

return QuerySet(
model=self._get_parent_model(model)
).only(*concrete_fields).annotate(**annotation_fields).query

def create_model(self, model, extra_field=None):
if self.model_is_materialized_view(model):
sql = self.sql[...]
Django Unleashed Framework
django.db.models import fields from django.db.models.expressions import Combinable, ExpressionWrapper, F class MaterializedViewField(fields.Field): def __init__(self, child, source=None, **kwargs): super().__init__(**kwargs) self.child = child if isinstance(source…
_create_materialized_view % {
'table': self.quote_name(self.model_meta(model).db_table),
'definition': self.get_queryset(model, extra_field=extra_field)
}
self.execute(sql)
else:
super().create_model(model)

def add_field(self, model: Model, field):

if self.model_is_materialized_view(model):
setattr(model, field.attname, field)
self.delete_model(model)
self.create_model(model, extra_field=field)

else:
super().add_field(model, field)

def remove_field(self, model, field):

if self.model_is_materialized_view(model):
delattr(model, field.attname)
self.delete_model(model)
self.create_model(model)
else:
super().remove_field(model, field)

def alter_field(self, model, old_field, new_field, strict=False):

if self.model_is_materialized_view(model):
delattr(model, old_field.attname)
self.delete_model(model)
self.create_model(model, extra_field=new_field)

else:
super().alter_field(model, old_field, new_field, strict)

def delete_model(self, model):
if self.model_is_materialized_view(model):
self.execute(
self.sql_delete_materialized_view % {
"table": self.model_meta(model).db_table
}
)
else:
super().delete_model(model)

def refresh_materialized_view(self, model: type[Model], concurrent=False):
"""
Выполняет запрос на обновление материализованного представления,
если было желательно заполнять данные представления по требованию.
"""
self.execute(self.sql_refresh_materialized_View % {
'view': model._meta.db_table,
'concurrently': 'CONCURRENTLY' if concurrent else ''
})

class DatabaseWrapper(base.DatabaseWrapper):
SchemaEditorClass = DatabaseSchemaEditor
Приведенный выше код переопределяет встроенный в Django класс схемы базы данных postgres для поддержки выполнения запросов, необходимых для создания материализованных представлений после выполнения команды migrate.

Короче говоря, все методы работы с базой данных были модифицированы, чтобы проверить, является ли модель моделью материализованного представления или моделью обычного класса. Если это модель материализованного представления, будет вызван метод get_queryset, чтобы сгенерировать необработанный SQL-запрос из родительской модели для создания или обновления материализованного представления. В противном случае родительский метод будет вызван как обычно.

Наконец, добавим пользовательский движок базы данных в настройки базы данных проекта следующим образом:
DATABASES = {
'default': {
'ENGINE': 'core.backends.db',
'HOST': '<db-host',
'NAME': '<db-name',
'USER': '<user',
'PASSWORD': '<passwrod',
'PORT': 5432,
'ATOMIC_REQUESTS': True,
}
}
Шаг 4. Собираем все вместе

Теперь продемонстрирую использование материализованного представления на нескольких примерах моделей. Определение модели в основном представляет собой простую модель Post с отношением “многие ко многим” с моделями Comment и Tag, как показано в примере ниже:
class Tag(models.Model):
name = models.CharField(max_length=100)

def __str__(self):
return self.name

class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'Comment by {self.author.username} on {self.post.title}'

class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
tags = models.ManyToManyField(Tag)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return self.title
Затем необходимо провести миграцию моделей, последовательно используя команды makemigrationsи migrate.
$ python manage.py makemigraitons
$ python manage.py migrate
После того как все модели перенесены в базу данных, нужно создать определение модели материализованного представлен[...]
Django Unleashed Framework
_create_materialized_view % { 'table': self.quote_name(self.model_meta(model).db_table), 'definition': self.get_queryset(model, extra_field=extra_field) } self.execute(sql) else: super().create_model(model) def add_field(self, model: Model, field): if s…
ия для модели Post.
class MaterializedViewBaseModel(models.Model):

class Meta:
abstract = True

@classmethod
def check(cls, **kwargs):
errors = super().check(**kwargs)

if not hasattr(cls._meta, 'materialized_view'):
errors.append(
checks.Error(
'The `view` attribute is required in materialized view meta class.',
obj=cls,
id='models.E100',
)
)

view_parent_model = getattr(cls._meta, 'view_parent_model', None)

if view_parent_model:
try:
apps.get_model(*getattr(cls._meta, 'view_parent_model').split('.'))
except (LookupError, ValueError) as e:
errors.append(
checks.Error(
f"Invalid `view_parent_model` format, {e}", obj=cls, id='models.E101'
)
)

else:
errors.append(
checks.Error(
'The `view_parent_model` attribute is required in materialized view meta class.',
obj=cls,
id='models.E101'
)
)

return errors

@classmethod
def refresh(cls, concurrent=False):
with connection.cursor() as cursor:
editor = cursor.db.schema_editor()
editor.refresh_materialized_view(cls, concurrent=concurrent)
class PostMaterializedView(MaterializedViewBaseModel):

post_id = MaterializedViewField(source='pk', child=models.IntegerField())
title = MaterializedViewField(child=models.CharField())
content = MaterializedViewField(child=models.CharField())
tag_names = MaterializedViewField(
source=aggregates.StringAgg('tags__name', delimiter="'; '", distinct=True),
child=models.CharField()
)
comments_count = MaterializedViewField(
source=functions.Coalesce(models.Count('comments', distinct=True), 0),
child=models.IntegerField()
)
comment_authors = MaterializedViewField(
source=aggregates.StringAgg(
'comments__author__first_name', delimiter="', '", distinct=True
),
child=models.CharField()
)

class Meta:
view_parent_model = 'api.Post'
materialized_view = True
constraints = [
models.UniqueConstraint(
models.F('post_id'), name='unique_post_id',
)
]
В приведенном выше примере пользовательские Optionsкласса Metaбыли определены для информирования редактора схемы базы данных о том, что модель является материализованным представлением, и генерации SQL-запроса из модели Post.

Поле модели MaterializedViewFieldбыло использовано для определения полей модели, предоставляющих поле дочерней модели и атрибут источника. Важно отметить, что поле модели было специально разработано для поддержки различных выражений запросов базы данных, упомянутых в документации Django, включая F, StringAggr, Count, Avg, Sum, Caseи так далее.

Материализованный абстрактный класс в основном выполняет проверки пользовательских атрибутов класса Meta. Например, проверяет существование атрибутов materialized_viewи view_parent_modelи уточняет был ли view_parent_modelопределен в правильном формате.

Наконец, последовательное выполнение команд makemigrationsи migrateдолжно создать новое материализованное представление, легко используемое в Django для выполнения запросов и операций фильтрации.
# Сгенерировано Django 4.2.1 2023.05.22 в 22:10

import api.fields
import django.contrib.postgres.aggregates.general
from django.db import migrations, models
import django.db.models.aggregates
import django.db.models.functions.comparison
class Migration(migrations.Migration):

dependencies = [
("api", "0001_initial"),
]

operations = [
migrations.CreateModel(
name="PostMaterializedView",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"post_id",
api.fields.MaterializedViewField(
child=models.IntegerField(),
source=models.ExpressionWrapper(
models.F("pk"), output_field=models.IntegerField()
),
),
),
(
"title",
api.fields.MaterializedViewField(
child=models.CharField(), source=None
),
),
(
"content",
api.fields.MaterializedViewField(
child=models.CharField(), source=Non[...]
Django Unleashed Framework
ия для модели Post. class MaterializedViewBaseModel(models.Model): class Meta: abstract = True @classmethod def check(cls, **kwargs): errors = super().check(**kwargs) if not hasattr(cls._meta, 'materialized_view'): errors.append( checks.Error( 'The `view`…
e
),
),
(
"tag_names",
api.fields.MaterializedViewField(
child=models.CharField(),
source=django.contrib.postgres.aggregates.general.StringAgg(
"tags__name", delimiter="'; '", distinct=True
),
),
),
(
"comments_count",
api.fields.MaterializedViewField(
child=models.IntegerField(),
source=django.db.models.functions.comparison.Coalesce(
django.db.models.aggregates.Count(
"comments", distinct=True
),
0,
),
),
),
(
"comment_authors",
api.fields.MaterializedViewField(
child=models.CharField(),
source=django.contrib.postgres.aggregates.general.StringAgg(
"comments__author__first_name",
delimiter="', '",
distinct=True,
),
),
),
],
options={
"materialized_view": True,
"view_parent_model": "api.Post",
},
),
migrations.AddConstraint(
model_name="postmaterializedview",
constraint=models.UniqueConstraint(
models.F("post_id"), name="unique_post_id"
),
),
]
Обратите внимание: атрибуты sourceи childполя MaterializedViewFieldбыли включены в файл миграции, так как мы определили их в методе deconstructполя.

Теперь Django успешно интегрирован с материализованными представлениями PostgreSQL.

Следующие шаги

Хотя нам удалось внедрить в Django новую функцию для использования материализованных представлений PostgreSQL, есть несколько улучшений, достойных обсуждения.

Поскольку теперь ясно, что материализованные представления нуждаются в регулярных обновлениях в случае, если базовая таблица представления была обновлена, необходимо разработать механизм для поддержания данных материализованного представления в актуальном состоянии.

На предложенном решении можно протестировать более сложные примеры, чтобы проверить его динамичность для различных типов запросов и случаев использования.

Заключение

Надеюсь, это руководство позволит вам легко интегрировать материализованные представления в приложения Django. Для этого потребуется запустить такие механизмы, как переопределение класса схемы базы данных, разработка пользовательских классов модели и разработка пользовательских полей модели.

Благодаря возможности создавать и обновлять материализованные представления с помощью системы миграции Django, вы сможете поддерживать синхронизацию между схемой базы данных и определениями моделей. Разделение обычных моделей и моделей материализованных представлений улучшает организацию и удобство сопровождения кода.
Читайте также:

* Как загружать файлы и изображения в приложении Django
* Как заказывали: админ-панель от Django Jet
* Простой прием для молниеносных запросов LIKE и ILIKE

Читайте нас в Telegram, VK и Дзен

Перевод статьи Abdulla Hashim: Integrating Django with PostgreSQL Materialized Views

Читать: Интеграция Django с материализованными представлениями PostgreSQL .
😱3🤔1
5 Django Commands Every Developer Should Know

django-admin startproject

This command is used to create a new Django project. It sets up the basic directory structure and configuration files for a Django project. For example, running django-admin startproject mylibrary will create a new project ...

Read: https://codepriest.hashnode.dev/5-django-commands-every-developer-should-know
Free Services to Support Development of a Django App I

Introduction
When we are hosting a website using cloud services, we know that the process can be quite expensive. So it makes sense for us to stick to as many free services as we can during the development phase.
Here are 5 different services that we...

Read: https://diptonil.hashnode.dev/free-services-to-support-development-of-a-django-app-i
Structuring Your Django Template The Right Way

Introduction
Templates play a vital role in Django's MVT (Model-View-Template) structure. In simple terms, a Django template is like a particular HTML file written in languages like HTML, CSS, and Javascript. These templates create the visual appeara...

Read: https://faithbolanle.hashnode.dev/structuring-your-django-template-the-right-way
Choosing the Right Framework: Laravel, Django, or React?

In the world of web development, selecting the right framework is crucial to ensure efficient and successful project outcomes. Laravel, Django, and React are three popular choices that developers often consider.
Before hardcore developer comes at me...

Read: https://scofield.hashnode.dev/choosing-the-right-framework-laravel-django-or-react
👍1
Python Web Development Explained: An In-Depth Look at Flask and Django

Hey there, fellow coders! Are you ready for an exciting deep-dive into the world of Flask and Django - two Python frameworks that are absolute game-changers in web development? Python, our trusty friend, is known for its simplicity and versatility, p...

Read: https://asksnehasish.hashnode.dev/mastering-web-dev-python-flask-django
👍1
Essential Django Commands for Web Development

Django is a powerful web framework that simplifies the process of building web applications. As a Django developer, it's important to be familiar with certain commands that can greatly enhance your productivity. In this blog post, we'll explore some ...

Read: https://kcihemelandu.hashnode.dev/essential-django-commands-for-web-development
How to Create an Empty Migration File in Django

Migrations are an essential part of Django, as they allow you to manage your database schema and ensure that it is consistent with your models. Most migrations capture actual changes to your models, but there are some scenarios where you may need to create an empty migration file.
In this article, we will show you how to create an empty migration …

Read: https://djangocentral.com/creating-an-empty-migration-file-in-django/