fix form templates

This commit is contained in:
sankalp committed 2025-02-16 13:47:57 +05:45
1 parent 830cd73e08
commit 07faec097e
6 files changed
+269 -310

No files matched your search

+92 -77
View File
@@ -1,11 +1,12 @@
from django.contrib import admin
from django import forms
from django.shortcuts import render, redirect
from django.urls import path
from django.urls import path, reverse
from django.http import JsonResponse
from django.contrib.admin import site
from .models import News, NewsImage, Category, SubCategory, Advertisement, Organization
@admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
list_display = ("id", "name", "location", "email", "phone_no", "logo")
@@ -30,87 +31,101 @@ class NewsImageInline(admin.TabularInline):
extra = 1
# class NewsAdminForm(forms.ModelForm):
# class Meta:
# model = News
# fields = ['title', 'description', 'image', 'category', 'sub_category']
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.fields['sub_category'].queryset = SubCategory.objects.none()
# # If we have an instance and category is set
# if self.instance and self.instance.pk and self.instance.category:
# self.fields['sub_category'].queryset = SubCategory.objects.filter(
# category=self.instance.category
# )
# # If form data is passed and category is selected
# if args and args[0] and 'category' in args[0]:
# try:
# category_id = int(args[0]['category'])
# self.fields['sub_category'].queryset = SubCategory.objects.filter(
# category_id=category_id
# )
# except (ValueError, TypeError):
# pass
class NewsAdminForm(forms.ModelForm):
class Meta:
model = News
fields = ["title", "description", "image", "category", "sub_category"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["sub_category"].queryset = SubCategory.objects.none()
# If we have an instance and category is set
if self.instance and self.instance.pk and self.instance.category:
self.fields["sub_category"].queryset = SubCategory.objects.filter(
category=self.instance.category
)
# If form data is passed and category is selected
if args and args[0] and "category" in args[0]:
try:
category_id = int(args[0]["category"])
self.fields["sub_category"].queryset = SubCategory.objects.filter(
category_id=category_id
)
except (ValueError, TypeError):
pass
@admin.register(News)
class NewsAdmin(admin.ModelAdmin):
# form = NewsAdminForm
form = NewsAdminForm
inlines = [NewsImageInline]
list_display = ['title', 'category', 'sub_category', 'created_at', 'updated_at']
# def get_urls(self):
# urls = super().get_urls()
# custom_urls = [
# path('add/', self.admin_site.admin_view(self.add_news_view), name='news_news_add'),
# path('get_subcategories/', self.admin_site.admin_view(self.get_subcategories), name='get_subcategories'),
# ]
# return custom_urls + urls
# def get_subcategories(self, request):
# category_id = request.GET.get('category_id')
# if category_id:
# subcategories = SubCategory.objects.filter(category_id=category_id).values('id', 'name')
# return JsonResponse(list(subcategories), safe=False)
# return JsonResponse([], safe=False)
# def add_news_view(self, request):
# if request.method == 'POST' and '_select_category' in request.POST:
# # Just handling category selection
# form = self.form(request.POST)
# if 'category' in request.POST and request.POST['category']:
# category_id = request.POST['category']
# form.fields['sub_category'].queryset = SubCategory.objects.filter(
# category_id=category_id
# )
# elif request.method == 'POST':
# # Final form submission
# form = self.form(request.POST, request.FILES)
# if form.is_valid():
# news = form.save()
# self.message_user(request, "News created successfully.")
# return redirect('admin:news_news_change', object_id=news.pk)
# else:
# form = self.form()
# # Get all categories for the dropdown
# categories = Category.objects.all()
# # Prepare context for the template
# context = {
# 'form': form,
# **site.each_context(request),
# 'categories': categories,
# 'opts': self.model._meta,
# 'has_view_permission': self.has_view_permission(request),
# 'has_add_permission': self.has_add_permission(request),
# 'has_change_permission': self.has_change_permission(request),
# 'has_delete_permission': self.has_delete_permission(request),
# 'app_label': self.model._meta.app_label,
# }
# return render(request, 'admin/app/news/add_form.html', context)
list_display = ["title", "category", "sub_category", "created_at", "updated_at"]
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path(
"add/",
self.admin_site.admin_view(self.add_news_view),
name="news_news_add",
),
path(
"get_subcategories/",
self.admin_site.admin_view(self.get_subcategories),
name="get_subcategories",
),
]
return custom_urls + urls
def get_subcategories(self, request):
category_id = request.GET.get("category_id")
if category_id:
subcategories = SubCategory.objects.filter(category_id=category_id).values(
"id", "name"
)
return JsonResponse(list(subcategories), safe=False)
return JsonResponse([], safe=False)
def add_news_view(self, request):
if request.method == "POST" and "_select_category" in request.POST:
# Just handling category selection
form = self.form(request.POST)
if "category" in request.POST and request.POST["category"]:
category_id = request.POST["category"]
form.fields["sub_category"].queryset = SubCategory.objects.filter(
category_id=category_id
)
elif request.method == "POST":
# Final form submission
form = self.form(request.POST, request.FILES)
if form.is_valid():
news = form.save()
self.message_user(request, "News created successfully.")
return redirect(reverse("admin:app_news_changelist"))
else:
form = self.form()
# Get all categories for the dropdown
categories = Category.objects.all()
# Prepare context for the template
context = {
"form": form,
**site.each_context(request),
"categories": categories,
"opts": self.model._meta,
"has_view_permission": self.has_view_permission(request),
"has_add_permission": self.has_add_permission(request),
"has_change_permission": self.has_change_permission(request),
"has_delete_permission": self.has_delete_permission(request),
"app_label": self.model._meta.app_label,
}
return render(request, "admin/app/news/add_form.html", context)
@admin.register(Advertisement)
class AdvertisementAdmin(admin.ModelAdmin):
+6 -4
View File
@@ -1,6 +1,7 @@
from django.db import models
from django_ckeditor_5.fields import CKEditor5Field
class Organization(models.Model):
name = models.CharField(max_length=255)
location = models.CharField(max_length=255)
@@ -45,10 +46,12 @@ class SubCategory(models.Model):
class News(models.Model):
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True, max_length=30000)
description = models.TextField(null=True, blank=True, max_length=30000)
image = models.ImageField(upload_to="news")
category = models.ForeignKey(Category, on_delete=models.CASCADE)
sub_category = models.ForeignKey(SubCategory, on_delete=models.CASCADE, null=True, blank=True)
sub_category = models.ForeignKey(
SubCategory, on_delete=models.CASCADE, null=True, blank=True
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -62,7 +65,7 @@ class News(models.Model):
class NewsImage(models.Model):
news = models.ForeignKey(News, on_delete=models.CASCADE, related_name="images")
image = models.ImageField(upload_to="news/images")
image = models.ImageField(upload_to="news/images", blank=True)
def __str__(self):
return f"Image for {self.news.title}"
@@ -77,7 +80,6 @@ class Advertisement(models.Model):
def __str__(self):
return str(self.id)
class Meta:
ordering = ["id"]
verbose_name_plural = "ads"
+121 -196
View File
@@ -1,212 +1,137 @@
{% extends "admin/change_form.html" %}
{% load i18n admin_urls static admin_modify %}
{% block extrahead %}
{{ block.super }}
<style>
/* Main container styling */
.jazzmin-form-wrapper {
padding: 20px;
width: 100%;
background-color: white;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
/* Form layout */
.form-grid {
display: grid;
grid-template-columns: 180px 1fr;
gap: 15px 20px;
align-items: start;
}
/* Field styling */
.field-wrapper {
margin-bottom: 20px;
}
.field-label {
font-weight: 600;
color: #333;
margin-top: 8px;
text-align: right;
}
.field-input {
width: 100%;
}
/* Input styling */
input[type="text"],
textarea,
select {
width: 100%;
max-width: 500px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #fff;
}
textarea {
min-height: 150px;
}
/* Error styling */
.field-error {
color: #e74c3c;
font-size: 0.9em;
margin-top: 4px;
}
/* Button styling */
.submit-row {
margin-top: 30px;
display: flex;
justify-content: center;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
{% extends 'admin/change_form.html' %}
{% load static %}
{% load widget_tweaks %}
{% block extrastyle %}
{{ block.super }}
<style>
.nav-tabs .nav-link { color: #444; }
.nav-tabs .nav-link.active {
color: #007bff;
border-bottom: 2px solid #007bff;
}
.field-label {
text-align: left;
margin-bottom: 5px;
.card {
box-shadow: 0 0 1px rgba(0,0,0,.125), 0 1px 3px rgba(0,0,0,.2);
margin-bottom: 1rem;
border-radius: .25rem;
}
}
</style>
.card-header {
background-color: #f8f9fa;
border-bottom: 1px solid rgba(0,0,0,.125);
padding: .75rem 1.25rem;
}
.card-body { padding: 1.25rem; }
.card-footer {
background-color: #f8f9fa;
border-top: 1px solid rgba(0,0,0,.125);
padding: .75rem 1.25rem;
}
.form-control:focus {
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}
</style>
{% endblock %}
{% block content %}
<div class="jazzmin-form-wrapper">
<form method="post" enctype="multipart/form-data" id="news_form" novalidate>
{% csrf_token %}
{% if errors %}
<div class="errornote" style="margin-bottom: 20px; padding: 10px; background-color: #fef2f2; border-left: 4px solid #e74c3c; color: #e74c3c;">
{% blocktranslate count counter=errors|length %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %}
{{ form.non_field_errors }}
</div>
{% endif %}
<div class="form-grid">
<!-- Title Field -->
<div class="field-label">{{ form.title.label }}:</div>
<div class="field-input">
{% if form.title.errors %}
<div class="field-error">{{ form.title.errors }}</div>
{% endif %}
{{ form.title }}
</div>
<!-- Description Field -->
<div class="field-label">{{ form.description.label }}:</div>
<div class="field-input">
{% if form.description.errors %}
<div class="field-error">{{ form.description.errors }}</div>
{% endif %}
{{ form.description }}
</div>
<!-- Image Field -->
<div class="field-label">{{ form.image.label }}:</div>
<div class="field-input">
{% if form.image.errors %}
<div class="field-error">{{ form.image.errors }}</div>
{% endif %}
{{ form.image }}
</div>
<!-- Category Field -->
<div class="field-label">{{ form.category.label }}:</div>
<div class="field-input">
{% if form.category.errors %}
<div class="field-error">{{ form.category.errors }}</div>
{% endif %}
<select name="category" id="{{ form.category.id_for_label }}" onchange="updateSubcategories(this.value)">
<option value="">---------</option>
{% for category in categories %}
<option value="{{ category.id }}" {% if form.category.value|stringformat:"s" == category.id|stringformat:"s" %}selected{% endif %}>
{{ category.name }}
</option>
{% endfor %}
</select>
</div>
<!-- Subcategory Field -->
<div class="field-label" id="subcategory_label" {% if not form.sub_category.queryset.exists %}style="display: none;"{% endif %}>
{{ form.sub_category.label }}:
</div>
<div class="field-input" id="subcategory_row" {% if not form.sub_category.queryset.exists %}style="display: none;"{% endif %}>
{% if form.sub_category.errors %}
<div class="field-error">{{ form.sub_category.errors }}</div>
{% endif %}
<div id="subcategory_container">
{{ form.sub_category }}
<div class="container-fluid">
<div class="card">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#general">General</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#news-images">News Images</a>
</li>
</ul>
</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="card-body">
<div class="tab-content">
<div class="tab-pane fade show active" id="general">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.title.id_for_label }}">{{ form.title.label }}</label>
{{ form.title|add_class:"form-control" }}
{% if form.title.errors %}<div class="invalid-feedback d-block">{{ form.title.errors }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="{{ form.category.id_for_label }}">{{ form.category.label }}</label>
<select name="category"
id="{{ form.category.id_for_label }}"
class="form-control"
onchange="updateSubcategories(this.value)">
<option value="">---------</option>
{% for category in categories %}
<option value="{{ category.id }}"
{% if form.category.value|stringformat:"s" == category.id|stringformat:"s" %}selected{% endif %}>
{{ category.name }}
</option>
{% endfor %}
</select>
{% if form.category.errors %}<div class="invalid-feedback d-block">{{ form.category.errors }}</div>{% endif %}
</div>
</div>
</div>
<div class="form-group" id="subcategory_wrapper" style="display: none;">
<label for="{{ form.sub_category.id_for_label }}">{{ form.sub_category.label }}</label>
<div id="subcategory_container">{{ form.sub_category }}</div>
</div>
<div class="form-group">
<label for="{{ form.description.id_for_label }}">{{ form.description.label }}</label>
{{ form.description|add_class:"form-control" }}
</div>
<div class="form-group">
<label for="{{ form.image.id_for_label }}">{{ form.image.label }}</label>
{{ form.image|add_class:"form-control-file" }}
</div>
</div>
<div class="tab-pane fade" id="news-images">
<div class="form-group">
<label>Upload Additional News Images</label>
<input type="file" name="news_images" multiple class="form-control">
</div>
</div>
</div>
</div>
<div class="card-footer text-right">
<button type="submit" class="btn btn-success">Save</button>
<button type="submit" name="_addanother" class="btn btn-info">Save and add another</button>
<button type="submit" name="_continue" class="btn btn-primary">Save and continue editing</button>
</div>
</form>
</div>
</div>
</div>
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
<div class="submit-row">
<input type="submit" name="_save" value="{% translate 'Save' %}" class="default" style="padding: 8px 16px; background-color: #2980b9; color: white; border: none; border-radius: 4px; cursor: pointer;" />
</div>
</form>
</div>
<script>
<script>
function updateSubcategories(categoryId) {
const labelElement = document.getElementById('subcategory_label');
const rowElement = document.getElementById('subcategory_row');
const wrapper = document.getElementById('subcategory_wrapper');
const container = document.getElementById('subcategory_container');
if (!categoryId) {
labelElement.style.display = 'none';
rowElement.style.display = 'none';
wrapper.style.display = 'none';
return;
}
// Show elements
labelElement.style.display = 'block';
rowElement.style.display = 'block';
// Show loading indicator
const container = document.getElementById('subcategory_container');
container.innerHTML = '<div style="color: #2980b9;">Loading subcategories...</div>';
// Fetch subcategories with AJAX
wrapper.style.display = 'block';
container.innerHTML = '<div class="text-info">Loading subcategories...</div>';
fetch(`{% url 'admin:get_subcategories' %}?category_id=${categoryId}`)
.then(response => response.json())
.then(data => {
if (data.length === 0) {
container.innerHTML = '<select id="{{ form.sub_category.id_for_label }}" name="sub_category"><option value="">No subcategories available</option></select>';
} else {
let selectHtml = `<select id="{{ form.sub_category.id_for_label }}" name="sub_category">`;
data.forEach(item => {
selectHtml += `<option value="${item.id}">${item.name}</option>`;
});
selectHtml += '</select>';
container.innerHTML = selectHtml;
}
let selectHtml = `<select name="sub_category" class="form-control">`;
selectHtml += `<option value="">Select Subcategory</option>`;
data.forEach(item => {
selectHtml += `<option value="${item.id}">${item.name}</option>`;
});
selectHtml += '</select>';
container.innerHTML = selectHtml;
})
.catch(error => {
container.innerHTML = '<div style="color: #e74c3c;">Error loading subcategories</div>';
console.error('Error:', error);
.catch(() => {
container.innerHTML = '<div class="text-danger">Error loading subcategories</div>';
});
}
// Initialize subcategories if category is already selected
document.addEventListener('DOMContentLoaded', function() {
const categorySelect = document.getElementById('{{ form.category.id_for_label }}');
if (categorySelect.value) {
updateSubcategories(categorySelect.value);
}
});
</script>
{% endblock %}
</script>
{% endblock %}
+17 -7
View File
@@ -2,11 +2,21 @@
from django.urls import path
from . import views
urlpatterns = [
path('news/', views.NewsListView.as_view(), name='news-list'),
path('news/<int:id>/', views.NewsDetailView.as_view(), name='news-detail'),
path('categories/', views.CategoryListView.as_view(), name='category-list'),
path('subcategories/', views.SubCategoryListView.as_view(), name='subcategory-list'),
path('advertisements/', views.AdvertisementListView.as_view(), name='advertisement-list'),
path('organization/', views.OrganizationListView.as_view(), name='organization-list'),
]
path("news/", views.NewsListView.as_view(), name="news-list"),
path("news/<int:id>/", views.NewsDetailView.as_view(), name="news-detail"),
path("categories/", views.CategoryListView.as_view(), name="category-list"),
path(
"subcategories/", views.SubCategoryListView.as_view(), name="subcategory-list"
),
path(
"advertisements/",
views.AdvertisementListView.as_view(),
name="advertisement-list",
),
path(
"organization/", views.OrganizationListView.as_view(), name="organization-list"
),
]
+20 -14
View File
@@ -4,49 +4,55 @@ from django.shortcuts import get_object_or_404
from rest_framework.exceptions import ValidationError
from django.db.models import Q
from .serializers import *
from .views import News, Category, SubCategory, Advertisement, Organization
from .models import News, Category, SubCategory, Advertisement, Organization
class NewsListView(generics.ListAPIView):
serializer_class = NewsSerializer
def get_queryset(self):
queryset = News.objects.all().order_by('-created_at')
category = self.request.query_params.get('category', None)
subcategory = self.request.query_params.get('subcategory', None)
queryset = News.objects.all().order_by("-created_at")
category = self.request.query_params.get("category", None)
subcategory = self.request.query_params.get("subcategory", None)
if category:
queryset = queryset.filter(
Q(category__name__iexact=category) |
Q(category__id=category)
Q(category__name__iexact=category) | Q(category__id=category)
)
if subcategory:
queryset = queryset.filter(sub_category_id=subcategory)
return queryset
class NewsDetailView(generics.RetrieveAPIView):
queryset = News.objects.all()
serializer_class = NewsSerializer
lookup_field = 'id'
lookup_field = "id"
class CategoryListView(generics.ListAPIView):
queryset = Category.objects.prefetch_related('subcategories')
queryset = Category.objects.prefetch_related("subcategories")
serializer_class = CategoryListSerializer
class SubCategoryListView(generics.ListAPIView):
serializer_class = SubCategorySerializer
def get_queryset(self):
queryset = SubCategory.objects.all()
category_id = self.request.query_params.get('category', None)
category_id = self.request.query_params.get("category", None)
if category_id:
queryset = queryset.filter(category_id=category_id)
return queryset
class AdvertisementListView(generics.ListAPIView):
queryset = Advertisement.objects.filter(is_active=True)
serializer_class = AdvertisementSerializer
class OrganizationListView(generics.ListAPIView):
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
+13 -12
View File
@@ -40,6 +40,7 @@ INSTALLED_APPS = [
"rest_framework",
"corsheaders",
"django_ckeditor_5",
"widget_tweaks",
]
@@ -79,24 +80,24 @@ CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
# Also ensure you have this setting
SESSION_COOKIE_SAMESITE = 'Lax' # or 'None' if needed
CSRF_COOKIE_SAMESITE = 'Lax' # or 'None' if needed
SESSION_COOKIE_SAMESITE = "Lax" # or 'None' if needed
CSRF_COOKIE_SAMESITE = "Lax" # or 'None' if needed
CSRF_TRUSTED_ORIGINS = [
'http://192.168.1.93:5173',
'http://192.168.18.4:5173',
'http://192.168.1.68:5173',
'http://192.168.1.87:5173',
'http://localhost:5173'
"http://192.168.1.93:5173",
"http://192.168.18.4:5173",
"http://192.168.1.68:5173",
"http://192.168.1.87:5173",
"http://localhost:5173",
]
if DEBUG:
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_SECURE = False
CORS_ALLOWED_ORIGINS = [
'http://192.168.1.93:5173',
'http://192.168.18.4:5173',
'http://192.168.1.68:5173',
'http://192.168.1.87:5173',
'http://localhost:5173'
"http://192.168.1.93:5173",
"http://192.168.18.4:5173",
"http://192.168.1.68:5173",
"http://192.168.1.87:5173",
"http://localhost:5173",
]
WSGI_APPLICATION = "newsportal.wsgi.application"