video player and model and video guide routing and stuff

This commit is contained in:
Parsa Nazer
2025-02-16 21:42:29 +03:30
parent d8f7be7772
commit 81df30c806
28 changed files with 531 additions and 25 deletions
+2 -1
View File
@@ -9,7 +9,7 @@ from django.contrib.postgres.fields import ArrayField
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from unfold.forms import AdminPasswordChangeForm from unfold.forms import AdminPasswordChangeForm
from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm from unfold.forms import AdminPasswordChangeForm, UserChangeForm, UserCreationForm
from utils.admin import ModelAdmin
class UserAddressInLine(TabularInline): class UserAddressInLine(TabularInline):
model = UserAddressModel model = UserAddressModel
extra = 0 extra = 0
@@ -36,6 +36,7 @@ class UserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin):
fieldsets = ( fieldsets = (
('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}), ('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}),
('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}), ('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}),
('دسترسی های وبسایت', {'fields': ('is_superuser', 'video_uploader'),}),
) )
empty_value_display = 'ثبت نشده' empty_value_display = 'ثبت نشده'
add_fieldsets = ( add_fieldsets = (
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-14 22:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0010_useraddressmodel_is_main'),
]
operations = [
migrations.AddField(
model_name='user',
name='video_uploader',
field=models.BooleanField(default=False),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-14 23:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0011_user_video_uploader'),
]
operations = [
migrations.AlterField(
model_name='user',
name='video_uploader',
field=models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش'),
),
]
+1
View File
@@ -50,6 +50,7 @@ class User(AbstractBaseUser, PermissionsMixin):
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام') date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف') otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف')
otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف') otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف')
video_uploader = models.BooleanField(default=False, help_text='اپلود کننده ی ویدیویی اموزشی پنل ادمین', verbose_name='اپلودر اموزش')
objects = UserManager() objects = UserManager()
USERNAME_FIELD = 'phone' USERNAME_FIELD = 'phone'
+1 -2
View File
@@ -1,12 +1,11 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from unfold.admin import ModelAdmin
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from utils.admin import ModelAdmin
@admin.register(BlogModel) @admin.register(BlogModel)
class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin): class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin):
+2 -2
View File
@@ -1,12 +1,12 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from unfold.admin import ModelAdmin
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from utils.admin import ModelAdmin
@admin.register(ProductChatModel) @admin.register(ProductChatModel)
class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin): class ProductChatAdmin(ModelAdmin, ImportExportModelAdmin):
+7 -1
View File
@@ -30,7 +30,7 @@ UNFOLD = {
}, },
"BORDER_RADIUS": "8px", "BORDER_RADIUS": "20px",
"SHOW_HISTORY": True, "SHOW_HISTORY": True,
"SHOW_VIEW_ON_SITE": True, "SHOW_VIEW_ON_SITE": True,
"ENVIRONMENT": "core.settings.environment_callback", "ENVIRONMENT": "core.settings.environment_callback",
@@ -93,6 +93,12 @@ UNFOLD = {
"icon": "dashboard", "icon": "dashboard",
"link": reverse_lazy("admin:index"), "link": reverse_lazy("admin:index"),
}, },
{
"title": _("آموزش استفاده از پنل"),
"icon": "school",
"link": reverse_lazy("admin:home_learnvideomodel_changelist"),
"badge": "utils.admin.new_learn_video_count",
},
{ {
"title": _("سفارشات"), "title": _("سفارشات"),
"icon": "shopping_cart", "icon": "shopping_cart",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -26,6 +26,7 @@ urlpatterns = [
path('tickets/', include('ticket.urls')), path('tickets/', include('ticket.urls')),
path('blogs/', include('blog.urls')), path('blogs/', include('blog.urls')),
path('order/', include('order.urls')), path('order/', include('order.urls')),
path('home/', include('home.urls')),
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
] ]
+33 -4
View File
@@ -1,14 +1,15 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from unfold.admin import ModelAdmin from unfold.admin import ModelAdmin as UnfoldModelAdmin
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from unfold.decorators import action, display
from django.utils.html import format_html
from unfold.decorators import display
from utils.admin import ModelAdmin
@admin.register(ShowCaseSlider) @admin.register(ShowCaseSlider)
class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin): class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin):
import_form_class = ImportForm import_form_class = ImportForm
@@ -24,6 +25,34 @@ class ShowCaseSliderAdmin(ModelAdmin, ImportExportModelAdmin):
} }
} }
@admin.register(LearnVideoModel)
class LearnVideoAdmin(UnfoldModelAdmin):
list_display = ['title', 'section', 'display_viewd']
search_fields = ['title', 'section']
compressed_fields = False
list_filter = ['section']
warn_unsaved_form = True
change_form_template = 'video_change_form_after.html'
formfield_overrides = {
ArrayField: {
"widget": ArrayWidget,
}
}
@display(description='دیده شده')
def display_viewd(self, instance):
if instance.viewd:
svg = f'<a href="/home/video/view/{instance.id}"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="green" d="M12 16q1.875 0 3.188-1.312T16.5 11.5t-1.312-3.187T12 7T8.813 8.313T7.5 11.5t1.313 3.188T12 16m0-1.8q-1.125 0-1.912-.788T9.3 11.5t.788-1.912T12 8.8t1.913.788t.787 1.912t-.787 1.913T12 14.2m0 4.8q-3.65 0-6.65-2.037T1 11.5q1.35-3.425 4.35-5.462T12 4t6.65 2.038T23 11.5q-1.35 3.425-4.35 5.463T12 19m0-2q2.825 0 5.188-1.487T20.8 11.5q-1.25-2.525-3.613-4.012T12 6T6.813 7.488T3.2 11.5q1.25 2.525 3.613 4.013T12 17"/></svg></a>'
else:
svg = f'<a href="/home/video/view/{instance.id}"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="#c30009" d="m19.1 21.9l-3.5-3.45q-.875.275-1.775.413T12 19q-3.35 0-6.125-1.8t-4.35-4.75q-.125-.225-.187-.462t-.063-.488t.063-.488t.187-.462q.55-.975 1.175-1.9T4.15 7L2.075 4.9Q1.8 4.625 1.8 4.213t.3-.713q.275-.275.7-.275t.7.275l17 17q.275.275.288.688t-.288.712q-.275.275-.7.275t-.7-.275M12 16q.275 0 .525-.025t.5-.1l-5.4-5.4q-.075.25-.1.5T7.5 11.5q0 1.875 1.313 3.188T12 16m0-12q3.35 0 6.138 1.813t4.362 4.762q.125.2.188.438t.062.487t-.05.488t-.175.437q-.475.925-1.062 1.75t-1.313 1.55q-.35.35-.825.325t-.825-.375l-2-2q-.175-.175-.225-.413t.025-.487q.1-.325.15-.625t.05-.65q0-1.875-1.312-3.187T12 7q-.35 0-.65.05t-.625.15q-.25.075-.5.025T9.8 7l-.825-.825q-.475-.475-.312-1.1t.787-.8q.625-.125 1.263-.2T12 4m1.975 5.65q.275.325.462.713t.238.812q.025.2-.15.275t-.325-.075l-2.05-2.05Q12 9.175 12.088 9t.287-.175q.475.05.875.263t.725.562"/></svg></a>'
return format_html(
svg
)
@admin.register(SliderModel) @admin.register(SliderModel)
class SliderAdmin(ModelAdmin, ImportExportModelAdmin): class SliderAdmin(ModelAdmin, ImportExportModelAdmin):
@@ -0,0 +1,25 @@
# Generated by Django 5.1.2 on 2025-02-14 21:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0005_alter_showcaseslider_description_and_more'),
]
operations = [
migrations.CreateModel(
name='LearnVideoModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('video', models.FileField(upload_to='learning_video/')),
],
options={
'verbose_name': 'ویدیوی اموزشی',
'verbose_name_plural': 'ویدیوی های اموزشی',
},
),
]
@@ -0,0 +1,29 @@
# Generated by Django 5.1.2 on 2025-02-14 21:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0006_learnvideomodel'),
]
operations = [
migrations.AddField(
model_name='learnvideomodel',
name='section',
field=models.CharField(default='', max_length=40, verbose_name='بخش مربوطه'),
preserve_default=False,
),
migrations.AlterField(
model_name='learnvideomodel',
name='title',
field=models.CharField(max_length=100, verbose_name='عنوان ویدیو'),
),
migrations.AlterField(
model_name='learnvideomodel',
name='video',
field=models.FileField(upload_to='learning_video/', verbose_name='ویدیو'),
),
]
@@ -0,0 +1,20 @@
# Generated by Django 5.1.2 on 2025-02-14 23:12
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('home', '0007_learnvideomodel_section_alter_learnvideomodel_title_and_more'),
]
operations = [
migrations.AddField(
model_name='learnvideomodel',
name='content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Related Model'),
),
]
@@ -0,0 +1,20 @@
# Generated by Django 5.1.2 on 2025-02-14 23:28
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('home', '0008_learnvideomodel_content_type'),
]
operations = [
migrations.AlterField(
model_name='learnvideomodel',
name='content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', unique=True, verbose_name='مدل مرتبط'),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-15 00:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0009_alter_learnvideomodel_content_type'),
]
operations = [
migrations.AddField(
model_name='learnvideomodel',
name='viewd',
field=models.BooleanField(default=False),
),
]
@@ -0,0 +1,24 @@
# Generated by Django 5.1.2 on 2025-02-15 07:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0010_learnvideomodel_viewd'),
]
operations = [
migrations.AddField(
model_name='learnvideomodel',
name='icon',
field=models.CharField(default='', max_length=30, verbose_name='ایکون'),
preserve_default=False,
),
migrations.AlterField(
model_name='learnvideomodel',
name='viewd',
field=models.BooleanField(default=False, verbose_name='تماشا شده'),
),
]
@@ -0,0 +1,20 @@
# Generated by Django 5.1.2 on 2025-02-16 17:45
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('home', '0011_learnvideomodel_icon_alter_learnvideomodel_viewd'),
]
operations = [
migrations.AlterField(
model_name='learnvideomodel',
name='content_type',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='مدل مرتبط'),
),
]
+36 -2
View File
@@ -1,6 +1,6 @@
from django.db import models from django.db import models
from product.models import ProductModel from product.models import ProductModel
from django.urls import reverse
class SliderModel(models.Model): class SliderModel(models.Model):
link = models.URLField(verbose_name='لینک') link = models.URLField(verbose_name='لینک')
@@ -45,4 +45,38 @@ class ShowCaseSlider(models.Model):
class Meta: class Meta:
verbose_name = 'مدل نمایش کیس' verbose_name = 'مدل نمایش کیس'
verbose_name_plural = 'مدل نمایش کیس ها' verbose_name_plural = 'مدل نمایش کیس ها'
from django.contrib.contenttypes.models import ContentType
class LearnVideoModel(models.Model):
title = models.CharField(max_length=100, verbose_name='عنوان ویدیو')
section = models.CharField(max_length=40, verbose_name='بخش مربوطه')
video = models.FileField(upload_to='learning_video/', verbose_name='ویدیو')
content_type = models.OneToOneField(
ContentType,
on_delete=models.CASCADE,
verbose_name='مدل مرتبط', blank=True, null=True, unique=True
)
icon = models.CharField(max_length=30, verbose_name='ایکون')
viewd = models.BooleanField(default=False, verbose_name='تماشا شده')
@property
def section_url(self):
if not self.content_type:
return None
app_label = self.content_type.app_label
model_name = self.content_type.model
try:
return reverse(f'admin:{app_label}_{model_name}_changelist')
except Exception:
return None
def __str__(self):
return self.title
class Meta:
verbose_name = 'ویدیوی اموزشی'
verbose_name_plural = 'ویدیوی های اموزشی'
+6
View File
@@ -0,0 +1,6 @@
from django.urls import path
from . import views
urlpatterns = [
path('video/view/<int:pk>', views.ChangeViewVideo.as_view(), name='product-chat-view'),
]
+10 -1
View File
@@ -1,10 +1,19 @@
from django.shortcuts import render from django.shortcuts import render, get_object_or_404, redirect
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from product.models import ProductModel, SubCategoryModel, DollorModel from product.models import ProductModel, SubCategoryModel, DollorModel
from product.serializers import SubCategorySerializer, DynamicProductSerializer from product.serializers import SubCategorySerializer, DynamicProductSerializer
from .serializers import * from .serializers import *
from .models import * from .models import *
from rest_framework import status from rest_framework import status
from django.views import View
class ChangeViewVideo(View):
def get(self, request, pk):
videomodel = get_object_or_404(LearnVideoModel, pk=pk)
videomodel.viewd = not videomodel.viewd
videomodel.save()
return redirect('admin:home_learnvideomodel_changelist')
class HomeView(APIView): class HomeView(APIView):
+2 -2
View File
@@ -1,12 +1,12 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from unfold.admin import ModelAdmin, TabularInline, StackedInline from unfold.admin import TabularInline, StackedInline
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from utils.admin import ModelAdmin
class OrderItemModelInline(StackedInline): class OrderItemModelInline(StackedInline):
model = OrderItemModel model = OrderItemModel
@@ -0,0 +1,17 @@
# Generated by Django 5.1.2 on 2025-02-14 21:23
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('order', '0004_alter_orderitemmodel_product'),
]
operations = [
migrations.AlterModelOptions(
name='orderitemmodel',
options={'verbose_name': 'ایتم سبد خرید', 'verbose_name_plural': 'ایتم های سبد خرید'},
),
]
+5 -6
View File
@@ -1,15 +1,14 @@
from django.contrib import admin from django.contrib import admin, messages
from .models import * from .models import *
from unfold.admin import ModelAdmin, TabularInline, StackedInline from unfold.admin import TabularInline, StackedInline
from home.models import LearnVideoModel
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from unfold.widgets import ( from unfold.widgets import UnfoldAdminColorInputWidget
UnfoldAdminColorInputWidget,
)
from unfold.decorators import action, display from unfold.decorators import action, display
from utils.admin import ModelAdmin
@admin.register(ProductVariant) @admin.register(ProductVariant)
class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin): class ProductVariantAdmin(ModelAdmin, ImportExportModelAdmin):
@@ -0,0 +1,166 @@
{% extends "admin/base_site.html" %}
{% load unfold %}
{% load i18n admin_urls static admin_modify %}
{% block extrahead %}{{ block.super }}
<script src="{% url 'admin:jsi18n' %}"></script>
{{ media }}
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="px-4 lg:px-8">
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
<ul class="flex flex-wrap">
{% url 'admin:index' as link %}
{% trans 'Home' as name %}
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
{% url 'admin:app_list' app_label=opts.app_label as link %}
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
{% if has_view_permission %}
{% url opts|admin_urlname:'changelist' as link %}
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.verbose_name_plural|capfirst %}
{% else %}
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=opts.verbose_name_plural|capfirst %}
{% endif %}
{% if add %}
{% blocktranslate trimmed with name=opts.verbose_name asvar breadcrumb_name %}
Add {{ name }}
{% endblocktranslate %}
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=breadcrumb_name %}
{% else %}
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=original|truncatewords:'18' %}
{% endif %}
</ul>
</div>
</div>
{% endblock %}
{% endif %}
{% block nav-global %}{% spaceless %}
{% if change and not is_popup %}
{% block object-tools-items %}
{% change_form_object_tools %}
{% endblock %}
{% endif %}
{% endspaceless %}{% endblock %}
{% block nav-global-side %}
{% if has_add_permission %}
{% include "unfold/helpers/add_link.html" %}
{% endif %}
{% endblock %}
{% block content %}
<div id="content-main" class="flex flex-col gap-4">
{% block form_before %}{% endblock %}
<div dir='rtl' class="bg-base-50 border border-base-200 border-dashed flex flex-col gap-4 p-4 rounded dark:bg-white/[.02] dark:border-base-700 lg:flex-row lg:justify-between w-full shrink-0 lg:items-center" style="justify-content: space-between;">
<div class="flex flex-col lg:flex-row lg:items-center">
<h2 class="font-semibold text-font-important-light text-base dark:text-font-important-dark flex items-center">
<span class="material-symbols-outlined md-18 mr-3 w-4.5 align-middle">{{original.icon}}</span>
<span class="align-middle" style="margin-right: 8px;">اموزش بخش {{original.content_type}}</span>
</h2>
</div>
<div class="flex lg:flex-row lg:items-center">
{% component "unfold/components/flex.html" with class="flex-col gap-4 lg:flex-row" %}
{% component "unfold/components/button.html" with href=original.section_url %}
نمایش بخش مربوطه
{% endcomponent %}
{% endcomponent %}
</div>
</div>
{% if adminform.model_admin.change_form_outer_before_template %}
{% include adminform.model_admin.change_form_outer_before_template %}
{% endif %}
<div class="border border-base-200 border-dashed mb-4 p-3 rounded dark:border-base-700 gap-1.5">
{% if original and original.video %}
<h3 style="display: flex; justify-content: center; align-items: center; width: 100%; padding: 5px 0;">
<a href="{{original.section_url}}" style="color: rgb(var(--color-primary-500)); margin-right: 5px;">
{{original.content_type}}
</a>
آموزش بخش
</h3>
<div style="display: flex;justify-content: center;align-items: center;width: 100%;padding: 25px 0px;">
<video controls style="border-radius: var(--border-radius,6px);width: 100%;max-width: 800px;">
<source src="{{ original.video.url }}" type="video/mp4">
</video>
</div>
{% else %}
<p>no video available.</p>
{% endif %}
</div>
{% if request.user.video_uploader %}
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}{% if form_url %}action="{{ form_url }}" {% endif %}method="post" id="{{ opts.model_name }}_form" {% if adminform.model_admin.warn_unsaved_form %}class="warn-unsaved-form"{% endif %} novalidate>
{% csrf_token %}
{% if adminform.model_admin.change_form_before_template %}
{% include adminform.model_admin.change_form_before_template %}
{% endif %}
{% block form_top %}{% endblock %}
<div>
{% if is_popup %}
<input type="hidden" name="{{ is_popup_var }}" value="1">
{% endif %}
{% if to_field %}
<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">
{% endif %}
{% include "unfold/helpers/messages/errornote.html" with errors=errors %}
{% include "unfold/helpers/messages/error.html" with errors=adminform.form.non_field_errors %}
{% block field_sets %}
{% for fieldset in adminform %}
{% if "tab" not in fieldset.classes %}
{% include 'admin/includes/fieldset.html' %}
{% endif %}
{% endfor %}
{% include "unfold/helpers/fieldsets_tabs.html" %}
{% endblock %}
{% block after_field_sets %}{% endblock %}
{% block inline_field_sets %}
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
{% endblock %}
{% block after_related_objects %}{% endblock %}
{% if adminform.model_admin.change_form_after_template %}
{% include adminform.model_admin.change_form_after_template %}
{% endif %}
{% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
{% block admin_change_form_document_ready %}
<script id="django-admin-form-add-constants" src="{% static 'admin/js/change_form.js' %}"{% if adminform and add %} data-model-name="{{ opts.model_name }}"{% endif %} async></script>
{% endblock %}
{% prepopulated_fields_js %}
</div>
</form>
{% endif %}
{% if adminform.model_admin.change_form_outer_after_template %}
{% include adminform.model_admin.change_form_outer_after_template %}
{% endif %}
{% block form_after %}{% endblock %}
</div>
{% endblock %}
+2 -2
View File
@@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from unfold.admin import ModelAdmin, TabularInline from unfold.admin import TabularInline
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
@@ -10,7 +10,7 @@ from unfold.contrib.filters.admin import (
ChoicesDropdownFilter, ChoicesDropdownFilter,
MultipleChoicesDropdownFilter, MultipleChoicesDropdownFilter,
) )
from utils.admin import ModelAdmin
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-14 21:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ticket', '0007_alter_ticket_ticket_category'),
]
operations = [
migrations.AlterField(
model_name='ticket',
name='ticket_category',
field=models.CharField(choices=[('finance_and_accounting', 'مالی و حسابداری'), ('user_profile', 'پروفایل کاربری'), ('order_tracking', 'پیگیری سفارش'), ('authentication', 'احراز هویت'), ('product', 'محصول'), ('bug_and_error_reporting', 'اعلام باگ و خطا در وبسایت'), ('other', 'سایر')], max_length=30, verbose_name='دسته بندی تیکت'),
),
]
+30 -2
View File
@@ -1,7 +1,7 @@
from order.models import OrderModel from order.models import OrderModel
from product.models import DollorModel, CommentModel from product.models import DollorModel, CommentModel
from ticket.models import Ticket from ticket.models import Ticket
from home.models import LearnVideoModel
def admin_pending_count(request): def admin_pending_count(request):
pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count() pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count()
@@ -15,4 +15,32 @@ def comment_count(request):
return CommentModel.objects.filter(review_status='not_reviwed').count() return CommentModel.objects.filter(review_status='not_reviwed').count()
def new_ticket_count(request): def new_ticket_count(request):
return Ticket.objects.filter(status__in=['open', 'in_progress']).count() return Ticket.objects.filter(status__in=['open', 'in_progress']).count()
def new_learn_video_count(request):
return LearnVideoModel.objects.filter(viewd=False).count()
from django.contrib import admin, messages
from unfold.admin import ModelAdmin
from home.models import LearnVideoModel
from import_export.admin import ImportExportModelAdmin
from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm
from unfold.decorators import action, display
from django.shortcuts import redirect
from django.contrib.contenttypes.models import ContentType
class ModelAdmin(ModelAdmin):
actions_list = ['redirect_to_learn']
@action(description=f"چگونگی استفاده این بخش")
def redirect_to_learn(self, request):
content_type = ContentType.objects.get_for_model(self.model)
try:
learn_video = LearnVideoModel.objects.get(
content_type=content_type,
)
return redirect(f'/admin/home/learnvideomodel/{learn_video.id}/change/')
except Exception as e:
messages.error(request, f"برای بخش {content_type} ویدیویی اپلود نشده است")
return redirect(f'/admin/home/learnvideomodel/')