Python Django Form Yardımı

djangoda bir site geliştiriyorum siteme tags özelliği eklemek istedim ama djangoya entegre etmeyi beceremedim bende html kısmında yaptım yani django form’dan bağımsız gerektiği zaman request.POST.getlist(‘tags’) ile request.POST olarak gelen verileri çekiyorum article’a kaydeteceğim zaman kaydetmeden önce article.tags = requst.POST.getlist(‘tags’) yapıyorum veya updateArticle fonksiyonum var bunun içinde form’u tanımlarken instance parametresini kullanıyorum update metodu olduğu için tahmin edebileceğiniz gibi django’dan bağımsız olduğu için bu gelmiyor bu yüzden bunu nasıl yapabileceğimde yardım etmenizi istiyorum kodlar aşağıdadır :

model.py :

from django.db import models
from ckeditor.fields import RichTextField
# Create your models here.

        
class Article(models.Model):
    author = models.ForeignKey("auth.User",on_delete = models.CASCADE,verbose_name = "Yazar")
    title = models.CharField(max_length = 120,verbose_name = "Başlık",default='Untitled Article')
    content = RichTextField()
    created_date = models.DateTimeField(auto_now_add=True,verbose_name="Oluşturulma Tarihi")
    tags = models.JSONField(default=list,blank=True,null=True,verbose_name="Etiket")
    image = models.ImageField(blank=True,null=True,verbose_name="Resim")


    def __str__(self):
        return self.title
       

forms.py :

from django.contrib import admin
from django.urls import path
from django import forms
from . models import *

class AddArticle(forms.ModelForm):
    #tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all(), widget=forms.CheckboxSelectMultiple)
    class Meta:
        model = Article
        fields = ["title", "content","image"]

    def clean(self):
        content = self.cleaned_data.get("content")
        
        if content is None or len(content) <= 50:
            raise forms.ValidationError("Makaleniz En Az 50 Karakter Olmak Zorundadır!")


class UpdateArticle(forms.ModelForm):
    class Meta:
        model = Article
        fields = ["title","content","image"]
    def clean(self):
        content = self.cleaned_data.get("content")
        
        if content is None or len(content) <= 50:
            raise forms.ValidationError("Makaleniz En Az 50 Karakter Olmak Zorundadır!")

views.py :

from django.shortcuts import render,redirect,HttpResponse
from . models import Article
from .forms import AddArticle,UpdateArticle
from django.contrib.auth.decorators import login_required
from django.contrib import messages
# Create your views here.


def index(request):
    return render(request,"index.html")

def articles(request):
    return render(request,"articles.html")

@login_required
def dashboard(request):
    articles = Article.objects.all()

    return render(request,"dashboard.html",{"articles":articles})

@login_required
def addArticle(request):

    form = AddArticle(request.POST or None,request.FILES or None)
    
    
    if (form.is_valid()):
        selected_tags = request.POST.getlist('tags')

        article = form.save(commit=False)

        article.author = request.user
        article.tags = selected_tags

        article.save()
        messages.success(request,"Makaleniz Başarıyla Yayınlandı!")
        return redirect("article:dashboard")


    
    
    return render(request,"addarticle.html",{"form":form})

@login_required
def deleteArticle(request,id):
    article = Article.objects.filter(id=id,author=request.user).first()

    if (article is not None):
        article.delete()
        messages.success(request,"Makaleniz Başarıyla Silindi!")
        return redirect("article:dashboard")
    else:
        messages.error(request,"Böyle Bir Makale Yok Veya Bunu Yapmaya Yetkiniz Yok!")
        return redirect("article:dashboard")
    
@login_required
def updateArticle(request,id):
    article = Article.objects.filter(id=id,author=request.user).first()
    selected_tags = request.POST.getlist('tags')
    form = UpdateArticle(request.POST or None,request.FILES or None,instance=article)
    if (form.is_valid()):
        article = form.save(commit=False)
        article.tags = selected_tags
        article.save()
        messages.success(request,"Makaleniz Başarıyla Güncellendi!")
        return redirect("article:dashboard")

    
    
    
    if (articles is not None):
        return render(request,"updateArticle.html",{"form":form})
    else:
        messages.error(request,"Böyle Bir Makale Mevcut Değil Veya Bunu Yapmaya Yetkiniz Yok!")
        return redirect("article:dashboard")
    
    

def articleDetail(request,id):
    articlesrecent = Article.objects.filter().order_by("-created_date")
    article = Article.objects.filter(id=id).first()
    return render(request,"articleDetail.html",{"articlesrecent":articlesrecent,"article":article})

addarticle.html :

{% extends "layout.html" %}

{% load crispy_forms_tags %}

{% block body %}
    <div class="container-fluid py-5">
        <div class="row justify-content-center">
            <div class="col-lg-12 col-xl-10"> <!-- Daha geniş kolon kullanımı -->
                <div class="card shadow-lg border-light">
                    <div class="card-header bg-primary text-white text-center">
                        <h3>Makale Ekleyin</h3>
                    </div>
                    <div class="card-body">
                        <form method="post" enctype="multipart/form-data">
                            {% csrf_token %}
                            <div class="form-group">
                                {{form.media}}
                                {{ form|crispy }}
                            </div>

                            <!-- Etiket Seçimi -->
                            <div class="form-group">
                                <label for="tags" class="font-weight-bold">Etiketler Seçin</label>
                                <select name="tags" id="tags" class="form-control" multiple>
                                    <option value="Web Design">Web Design</option>
                                    <option value="HTML">HTML</option>
                                    <option value="CSS">CSS</option>
                                    <option value="JavaScript">JavaScript</option>
                                    <option value="PHP">PHP</option>
                                    <option value="Django">Django</option>
                                    <option value="Flask">Flask</option>
                                    <option value="React">React</option>
                                    <option value="NodeJS">NodeJS</option>
                                    <option value="Angular">Angular</option>
                                    <option value="Python">Python</option>
                                    <option value="Perl">Perl</option>
                                    <option value="R">R</option>
                                    <option value="Rust">Rust</option>
                                    <option value="Ruby">Ruby</option>
                                    <option value="Go">Go</option>
                                    <option value="Assembly">Assembly</option>
                                    <option value="Swift">Swift</option>
                                    <option value="Kotlin">Kotlin</option>
                                    <option value="Java">Java</option>
                                    <option value="C#">C#</option>
                                    <option value="C">C</option>
                                    <option value="C++">C++</option>
                                    <option value="PyQt">PyQt</option>
                                    <option value="Pygame">PyGame</option>
                                    <option value="Selenium">Selenium</option>
                                    <option value="Unity">Unity</option>
                                    <option value="Unreal Engine">Unreal Engine</option>
                                </select>
                                <small class="form-text text-muted">Birden fazla etiket seçebilirsiniz.</small>
                            </div>

                            <br>

                            <button class="btn btn-success btn-lg btn-block" type="submit">Ekle</button> <!-- Büyük buton -->
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Select2 CSS ve JS dosyaları dahil ediliyor -->
    <link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" />
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script>

    <script>
        $(document).ready(function() {
            // Select2'yi tags alanına uygulama
            $('#tags').select2({
                placeholder: "Etiketler Seçin",
                allowClear: true
            });
        });
    </script>

    <style>
        .card {
            border-radius: 12px; /* Kartın yuvarlak köşeleri */
        }

        .card-header {
            border-top-left-radius: 12px;
            border-top-right-radius: 12px;
            padding: 2rem 1rem; /* Başlık daha büyük ve dikkat çekici */
        }

        .card-body {
            padding: 3rem; /* İçerik alanı genişletildi */
        }

        .btn {
            font-size: 20px; /* Buton font büyüklüğü */
            padding: 15px;  /* Butonun iç padding'ini artırma */
        }

        .container-fluid {
            padding-left: 15px;
            padding-right: 15px;
        }

        h3 {
            font-size: 2.5rem; /* Başlık fontunu büyütme */
            font-weight: bold; /* Başlık kalın yapıldı */
        }

        .form-group {
            margin-bottom: 25px; /* Form elemanları arasında daha fazla boşluk */
        }

        input, textarea {
            font-size: 1.2rem; /* Form elemanlarının yazı boyutunu artırma */
            padding: 15px; /* Form elemanları için padding artırıldı */
            border-radius: 8px; /* Alan köşeleri yuvarlak */
            width: 100%; /* Form elemanları tam genişlikte */
            border: 1px solid #ccc;
        }

        textarea {
            resize: vertical; /* Yalnızca dikey olarak yeniden boyutlandırılabilir */
            min-height: 200px; /* Textarea için minimum yükseklik */
        }

        .form-group label {
            font-weight: bold; /* Etiketleri kalın yap */
        }

        /* Başka görsel detaylar */
        .card-header h3 {
            text-transform: uppercase; /* Başlık tamamen büyük harf olacak */
        }
    </style>
{% endblock %}

Basitçe açıklar mısın lütfen. Nerede sorun yaşıyorsun

anlatmak istediğim şu şimdi models kısmında tags’ler gördüğün gibi jsonfield olarak tutuluyor ve formda modelform yani bir modelle ilişkili o modelde article modeli ve form kısmında fields listesi ile görünmesini istediğim fieldlar gözüküyor title content image vs. ama ben burada json field kısmını gösteremiyorum hiç güzel gözükmüyor çünkü bende select etiketi ile yapıyorum eee dolayısıyla bu etiket kısmı django formla alakası kalmıyor benim kendi elimle eklediğim dinamik olmayan bir yapıya dönüşüyor mesela backend kısmında article’ı kaydetmek istiyorum diyelim article = form.save() ile yapabilecekken bunu yapmadan önce article.tags = request.POST.gelist(‘tags’) diyerek veriyi çekmem gerekiyor yani manuel sadece bu olsa geçerim ama mesela attığım koddaki articleUpdate fonksiyonunda update işlemi olduğu için instance = article yapıyorum ama dediğim gibi tags özelliği tamamen formdan ayrı olduğu için instance özelliği biliyorsunuz ki verilen objenin verilerini bu forma taşıyor ama tags kısmı bu formdan tamamen ayrı olduğu için taşınamıyor yani özetle bu etiket (tags) seçme kısmını django’ya eklemek istiyorum böyle harici bir sistem ile yapmak istemiyorum bu ne kadar büyük bir sorun tartışılır ama hoş gözükmüyor açıkçası.Yine anlatamadım gibi ama daha nasıl anlatılır inanın bilmiyorum

ben tam anlamadım; ama signal kullanarak yapabilir misin baktın mı? Ya da save metodunu override etmeyi denedin mi?

ek okuma: geeksforgeeks: Django Signals vs. Overriding Save Method

tags fieldını direkt Articles modelinde tutmaktansa Tag adında ayrı bir model oluşturup orada tutmak daha mantıklı olacaktır diye düşünüyorum. örneğin:

class Tag(models.Model):
    tag_title = models.CharField(max_length = 50)

class ArticleTag(models.Model):
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
    article = models.ForeignKey(Article, on_delete=models.CASCADE)

bu şekilde tanımlanan tablolara yanlış hatırlamıyorsam junction table deniyordu. işleri epey kolaylaştırıyor.
mesela siz JSONField kullanmışsınız. bu hem sorgularınızı zorlaştırır hem aynı tag defalarca kaydedilmiş olur.

1 Beğeni

ArticleTag ile yapmak istediğin şeyi ManyToManyField yapmıyor mu zaten?

django orm çok fazla kullanmadım. daha çok sqlalchemy kullanıyorum. orada bu şekilde yapıyorum genelde. bir yerde djangonun bu tip junction tableları manytomanyfield ile kendisinin oluşturduğunu okudum diye hatırlıyorum. dediğin doğru olabilir.