یک توسعه‌دهنده

یک توسعه دهنده که بیشتر از توسعه،‌ فیلم می‌بینه و کتاب می‌خونه :)

نکته‌های جنگویی - واحد زیباسازی فرم

سه شنبه, ۴ شهریور ۱۳۹۹، ۱۰:۱۳ ب.ظ

در ادامه‌ی نکته‌های جنگویی، در این پست به سراغ ساختن یه فرم برای اضافه کردن داستان میرم. اگر که پایه‌ی پروژه رو ندارید، این پست رو ببینید.

برای ساختن فرم، فایل 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. با تشکر از این واحد.

 

پایان./

نظرات (۱)

با تشکر . افزودن دکمه ثبت از خود کلاس فرم چه مزیتی میتونه داشته باشه ؟

پاسخ:
سلام. الان داشتم داکیومنت جنگو رو در این مورد میخوندم ولی حقیقتش مطلبی در این مورد پیدا نکردم؛ و اینکه تو داکیومنت، دکمه رو داخل html آورده بودن. حدس میزنم اگر دکمه رو داخل فرم استفاده کنید برای تنظیم کردن قرارگیریشون تو صفحه کار رو راحت‌تر میکنه، به شرط اینکه تمام فیلدها رو تو فرم لایه‌بندی کنیم. منظورم از لایه‌بندی خوندن مطالب بعد از Custom Crispy Field این لینکه:
https://simpleisbetterthancomplex.com/tutorial/2018/11/28/advanced-form-rendering-with-django-crispy-forms.html
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی

تمام حقوق مادی و معنوی این وبلاگ متعلق به وبلاگ سرزمین برنامه نویسی بوده و هر گونه کپی بردای بدون ذکر منبع غیرمجاز و از نظر ما حرام است