نکتههای جنگویی - واحد زیباسازی فرم
در ادامهی نکتههای جنگویی، در این پست به سراغ ساختن یه فرم برای اضافه کردن داستان میرم. اگر که پایهی پروژه رو ندارید، این پست رو ببینید.
برای ساختن فرم، فایل forms.py رو به اپ اضافه میکنم:
stories ├── admin.py ├── apps.py ├── forms.py ├── __init__.py ├── models.py ├── templates │ └── stories │ ├── add.html │ ├── detail.html │ └── index.html ├── tests.py ├── urls.py └── views.py
کدهایی که لازمه در forms.py بنویسم:
from django import forms from .models import Story class StoryForm(forms.ModelForm): class Meta: model = Story fields = ('title', 'body') labels = { 'title': "عنوان", 'body': "متن داستان", } widgets = { 'body': forms.Textarea() }
اینجا من از Modelform استفاده کردم روش دیگه اینه که از Form استفاده کنم مثل کد زیر:
from django import forms from .models import Story class StoryForm(forms.Form): title = forms.CharField(widget=forms.TextInput, label='عنوان') body = forms.CharField(widget=forms.Textarea, label='متن داستان')
که من با همون روش اولی راحتترم.
بعد از این مرحله stories/views.py رو تغییر میدم، و این متد اضافه کردن داستان رو اضافه میکنم:
from .forms import StoryForm from django.contrib.auth.decorators import login_required from django.utils.text import slugify from django.utils.crypto import get_random_string
فرمی که ساختم رو به views اضافه میکنم و چندتا متد دیگه که از اسمشون میتونین حدس بزنین برای چی استفاده میشن رو هم وارد میکنم.
و متد اضافه کردن داستانم میشه این:
@login_required def add_story(request): if request.method == 'POST': if request.user.is_superuser: form = StoryForm(request.POST) if form.is_valid(): story = form.save(commit=False) story.user = request.user story.slug = slugify(get_random_string(length=16)) story.save() return redirect('stories:add_story') else: form = StoryForm() return render(request, 'stories/add.html', {'form': form})
متدی که ساختم رو به stories/urls.py اضافه میکنم:
from django.urls import path from . import views app_name = 'stories' urlpatterns = [ path('add/', views.add_story, name='add_story'), ]
حالا میبایست یه کتابخونه نصب کنم:
pip3 install django-crispy-forms
بعد داخل A/settings.py به INSTALLED_APPS اضافهش میکنم:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # My Django apps 'stories.apps.StoriesConfig', # Thord-Party apps 'crispy_forms', ]
و این تنظیم رو هم پایین فایل A/settings.py برای این اضافه میکنم که مشخص کنم میخوام از bootstrap4 استفاده کنم:
CRISPY_TEMPLATE_PACK = 'bootstrap4'
در مورد crispy هم خود داکیومنتش اینطوری نوشته:
django-crispy-forms provides you with a
|crispy
filter and{% crispy %}
tag that will let you control the rendering behavior of your Django forms in a very elegant and DRY way. Have full control without writing custom form templates. All this without breaking the standard way of doing things in Django, so it plays nice with any other form application.
که اگه میخواید کامل بدونید چه امکاناتی داره میتونید داکیومنتش رو بخونید.
و در نهایت با استفاده از crispy قالب add.html رو مینویسم:
{% load crispy_forms_tags %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>اضافه کردن داستان</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1 class="text-center mt-5">افزودن داستان</h1> <hr> <div class="row" > <div class="col-4 mx-auto" style="direction: rtl;"> <form action="" method="post"> {{ form|crispy }} <input type="submit" class="btn btn-success btn-block" value="افزودن"> {% csrf_token %} </form> </div> </div> </div> </body> </html>
اگه بخوام تکتک فیلدها رو دستی تنظیم کنم کدم به شکل زیر میشه:
{% load crispy_forms_tags %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>اضافه کردن داستان</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1 class="text-center mt-5">افزودن داستان</h1> <hr> <div class="row" > <div class="col-4 mx-auto" style="direction: rtl;"> <form action="" method="post"> <div class="row"> <div class="col-6"> {{ form.title|as_crispy_field }} </div> <div class="col-6"> {{ form.body|as_crispy_field }} </div> </div> <input type="submit" class="btn btn-success btn-block" value="افزودن"> {% csrf_token %} </form> </div> </div> </div> </body> </html>
که فیلد عنوان و متن داستان تو یه سطر قرار میگیرن.
نکتهی آخر اینکه بهجای اینکه یه دکمه رو توی html بسازیم میتونیم تو خود فرمها بسازیم:
class StoryForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_method = 'post' self.helper.add_input(Submit('submit', 'افزودن', css_class='btn-success btn-block')) class Meta: model = Story fields = ('title', 'body') labels = { 'title': "عنوان", 'body': "متن داستان" } widgets = { 'body': forms.Textarea() }
و اینکه شیوهی فراخوانی فرم تو add.html به شکل زیر حتما و باید تغییر کنه:
{% load crispy_forms_tags %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>اضافه کردن داستان</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1 class="text-center mt-5">افزودن داستان</h1> <hr> <div class="row" > <div class="col-4 mx-auto" style="direction: rtl;"> <form action="" method="post"> {% crispy form %} {% csrf_token %} </form> </div> </div> </div> </body> </html>
شخصا اینطوری نمیپسندم، ولی خب اینم یکی از راههاست. حتا شما میتونید قاببندی و جایگیری فیلدها رو هم توی forms.py تغیین کنید، که برای اینکار توصیه میکنم این مطلب رو بخونید و خودم رو از نوشتنش معاف میکنم =))
و این بود واحد زیباسازی فرم جنگو با استفاده از django-crispy-forms. با تشکر از این واحد.
پایان./
با تشکر . افزودن دکمه ثبت از خود کلاس فرم چه مزیتی میتونه داشته باشه ؟