لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 08/16/18 في كل الموقع
-
بعد أن تعرّفنا على طريقة تمرير قيم المُتغيّرات من بايثون إلى ملفّات HTML أصبح بإمكاننا أن نستعمل قاعدة بيانات تحتوي على جدول للمقالات عوضا عن استعمال قائمة أو قاموس. ما هي قاعدة البيانات قاعدة البيانات ببساطة مخزَن للبيانات المُختلفة كأسماء المستخدمين، كلمات المرور، وباقي القيم التي يُمكن أن تحصل عليها ممن يستخدم تطبيقك، ويُمكن كذلك جلب، تعديل وحذف البيانات منها بسهولة. يُمكن أن تكون قاعدة البيانات عبارة عن ملفّ نصي بسيط، بحيث يمثل كل سطر منه قيمة مُستقلّة، ويُمكن أن تكون عبارة عن جدول، بحيث يكون لهذا الجدول أعمدة وخانات، في كلّ عمود نوع محدد من القيم، وفي كلّ خانة القيمة الخاصّة بهذا النوع. سنستخدم في هذا الدّرس نظام SQL لقواعد البيانات، وهو نظام يعتمد على الجداول، وسنستخدم في هذا الدّرس جدولا لتخزين المقالات كالتّالي: رقم المُعرّف عنوان المقال مُحتوى المقال 1 عنوان المقال الأول مُحتوى المقال الأول 2 عنوان المقال الثّاني مُحتوى المقال الثّاني بنية تطبيق "مدونتي" سنعمل في هذا الدّرس على بناء تطبيق مُتكامل يُمكن أن يعمل كنظام إدارة مُحتوى بسيط، ستكون بنية التّطبيق كالآتي: الصّفحة الرّئيسيّة: هنا تُعرض عناوين ومحتويات المقالات المُتواجدة في قاعدة البيانات، بالإضافة إلى زر لحذف كل مقال. صفحة المقال: هنا ستتمكن من قراءة المقال مع رابط تحت المقال لحذفه. إضافة مقال جديد: ستتمكّن من إضافة مقال جديد إلى قاعدة البيانات في الصّفحة الرّئيسيّة مباشرة بعد عرض المقالات الموجودة. وهذه صور للتّطبيق النّهائي: الصفحة الرئيسية صفحة المقال إنشاء قاعدة البيانات وإنشاء جدول المقالات سنستعمل في الدّرس قواعد البيانات Sqlite لإدارة قاعدة البيانات، وذلك لسهولة التّعامل معها وسهولة نقل ملفّات قاعدة البيانات إلى أجهزة أخرى، كما أنّها لا تعمل على خادوم كما هو الحال مع MySQL أو Postgresql. تنويه: من المُفضّل عدم استخدام Sqlite في التّطبيقات التي ستنشرها على الأنترنت أو المشاريع الرّسميّة، ومن المُفضّل استخدام Postgresql أو MySQL في هذه الحالة. سننشئ قاعدة بيانات باسم database. في قاعدة البيانات هذه سنضيف جدولا للمقالات باسم posts. سيتكون جدول المقالات من ثلاثة أعمدة: رقم المقال/المعرّف (ID) عنوان المقال (Title) مُحتوى المقال (Content) لإنشاء قاعدة البيانات وجدول المقالات يُمكنك تنفيذ الشيفرة التّالية، ضعها داخل ملفّ باسم create_db.py وقم بتنفيذه: # -*- coding: utf-8 -*- import sqlite3 # الاتّصال بقاعدة البيانات db = sqlite3.connect('database.db') # إنشاء مُؤشّر في قاعدة البيانات لنتمكّن من تنفيذ استعلامات SQL cursor = db.cursor() # إنشاء الجدول cursor.execute(""" CREATE TABLE posts( id INTEGER PRIMARY KEY, title CHAR(200), content TEXT )""") # إدخال القيم إلى الجدول cursor.execute('''INSERT INTO posts(title, content) VALUES(?,?)''', (u'عنوان المقال الأول', u'محتوى المقال الأول')) cursor.execute('''INSERT INTO posts(title, content) VALUES (?,?)''', (u'عنوان المقال الثّاني', u'مُحتوى المقال الثّاني')) # تطبيق التغييرات db.commit() لاحظ بأنّنا نستدعي الوحدة sqite3 في البداية، وذلك لتنفيذ شيفرة لغة SQL، والشيفرة الممرّرة كمُعاملات للدّالة execute هي شيفرة SQL خاصّة بقاعدة البيانات Sqlite. بعد تنفيذ الشيفرة سنحصل على ملف database.db وهو الذي سيكون قاعدة بيانات التّطبيق، يوجد داخل قاعدة البيانات جدول مقالات باسم posts يحتوي بدوره على 3 أعمدة (رقم مُعرّف المقال، عنوان المقال ومحتواه)، مُعرّف المقال سيزيد بواحد تلقائيّا في كلّ مرّة نُضيف فيها عنوانا ومحتوى جديدين وهذا لأنّه من النّوع PRIMARY KEY، ما يعني بأنّنا نستطيع توفير قيمتين فقط دون الاهتمام بخانة رقم المعرّف. نضيف بعد ذلك مقالين: المقال الأول: عنوانه "عنوان المقال الأول"، مُحتواه "محتوى المقال الأول" المقال الثاني: عنوانه "عنوان المقال الثاني"، مُحتواه "محتوى المقال الثّاني" بعد الانتهاء من إضافة القيم، نقوم باستدعاء الدّالة commit لحفظ التّغييرات إلى قاعدة البيانات. الحصول على المقالات للحصول على رقم مُعرّف وعنوان ومحتوى المقالات يُمكننا تنفيذ الاستعلام التّالي: SELECT * FROM posts; النّجمة عبارة تعني all أو الكل. يُمكننا كذلك الحصول على قيم عمود واحد فقط: SELECT title FROM posts; ويُمكن الحصول على أكثر قيم أكثر من عمود: SELECT title, content FROM posts; لوضع القيم في مُتغيّر وإرجاعه في دالة في بايثون يُمكنك كتابة دالة كالتّالي: import sqlite3 BASE_DIR = path.dirname(path.realpath(__file__)) DB_PATH = path.join(BASE_DIR, 'database.db') def get_posts(): db = sqlite3.connect(DB_PATH) cursor = db.cursor() query = cursor.execute('''SELECT * FROM posts''') posts = query.fetchall() return posts السّطر الأول يستورد مكتبة sqlite3. السّطر الثّاني مسؤول عن الحصول على مسار المُجلّد الحالي، بعدها نقوم بإيصال مسار المُجلّد الحالي مع ملفّ قاعدة البيانات لنحصل على المسار الكامل للملفّ كقيمة للمُتغيّر DB_PATH، وهذا لتفادي بعض الأخطاء التّي قد تحدث عند نقل ملفّات التّطبيق إلى مكان آخر كاستضافة ما أو نظام تشغيل مُختلف. أما الدالة فتقوم أولا بالاتصال بقاعدة البيانات بالدّالة connect ومعامل DB_PATH الذي يُمثّل مسار ملف قاعدة البيانات database.db، بعدها نُنشئ مؤشّرا بالدّالة cursor، ثمّ ننفّذ الاستعلام كمُعامل مُمرّر للدّالة execute، بعدها نُطبّق الدالّة fetchall على نتيجة الاستعلام للحصول على القيم في قائمة من المجموعات، بحيث تحتوي القائمة على مجموعة بثلاثة عناصر العنصر الأول هو رقم المعرّف والعنصر الثّاني يمثّل عنوان المقال والعنصر الثّالث يمثّل محتوى المقال. وبالتّالي فإنّنا سنتمكن من الوصول إلى محتويات المقال كعناصر في مجموعة داخل قائمة، والقائمة تحتوي على العديد من المجموعات. قائمة المقالات ستكون كالتّالي: posts = [(1, u'عنوان المقال الأول', u'محتوى المقال الأول'), (2, u'عنوان المقال الثّاني', u'محتوى المقال الثّاني') ] ما يعني بأنّنا نستطيع الوصول إلى مُعرّف كل مقال، عنوانه ومحتواه بحلقة For بسيطة: posts = get_posts() for post in posts: post[0] # رقم المعرّف post[1] # عنوان المقال post[2] # محتوى المقال احفظ الدّالة get_posts في ملفّ باسم manage_db.py لنستعملها لاحقا كوحدة مع تطبيقنا (انظر درس الوحدات والحزم في لغة بايثون). الحصول على مقال حسب معرفه/رقمه للحصول على مقال حسب رقم مُعرّفه يكفي أن نُضيف جملة WHERE إلى استعلام SQL: SELECT title, content FROM posts WHERE id=1 ستُمكّننا الجملة أعلاه من الحصول على عنوان ومحتوى المقال الذي يمتلك رقم المُعرّف 1. لاستغلال الأمر في لغة بايثون بمُساعدة وحدة sqlite يُمكننا أن نكتب دالة باسم get_post_by_id لنحصل على مقال حسب رقم مُعرّفه، وبالطّبع سيكون للدّالة مُعامل واحد باسم post_id ليحمل قيمة رقم المُعرّف. def get_post_by_id(post_id): db = sqlite3.connect(DB_PATH) cursor = db.cursor() post_id = int(post_id) query = cursor.execute('''SELECT title, content FROM posts WHERE id=?''',(post_id,)) post = query.fetchone() return post بعد الاتّصال بقاعدة البيانات وإنشاء مؤشّر، نقوم أولا بتحويل قيمة رقم المُعرّف إلى عدد صحيح لأن الدّالة رقم المعرّف في قاعدة البيانات عبارة عن عدد صحيح. بعدها نُنفّذ الاستعلام الذي سبق وأن ذكرناه، لكن هذه المرّة قُمنا بتمرير مجموعة من عنصر واحد، وهذا العنصر هو مُعامل الدّالة، بعدها عرّفنا مُتغيّرا باسم post ليحمل بيانات المقال التي حصلنا عليها بتنفيذ الدّالة fetchone على الاستعلام، بعدها نُرجع المُتغيّر post. إذا استدعيت الدّالة مع تمرير قيمة بالعدد 1 فسيكون المُخرج كالتّالي: (u'عنوان المقال الأول', u'محتوى المقال الأول') أضف الدالة get_post_by_id إلى ملفّ manage_db.py واحفظه. حذف مقال حسب رقم المقال طريقة حذف المقال مُشابهة لطريقة الحصول عليه، فقط استبدل SELECT بالأمر DELETE. DELETE FROM posts WHERE id=? ما يعني بأنّنا نستطيع كتابة دالة في لغة بايثون لحذف مقال حسب رقم مُعرّفه: def delete(post_id): db = sqlite3.connect(DB_PATH) cursor = db.cursor() cursor.execute('''DELETE FROM posts WHERE id=?''', (post_id,)) db.commit() الاختلاف هنا هو أنّنا سنحتاج إلى تنفيذ الدّالة commit لتأكيد العمليّة. وكما العادة، أضف دالة الحذف إلى ملفّ manage_db.py. إضافة مقال تعرّفنا في بداية هذا الدّرس على طريقة إضافة مقال إلى قاعدة البيانات. INSERT INTO posts(title, content) VALUES('Title 1','Content 1') يُمكننا في بايثون إدخال قيم المُتغيّرات إلى قاعدة البيانات بالطّريقة التّالية: import sqlite3 db = sqlite3.connect('database.db') cursor = db.cursor() title_variable = 'Title 3' content_variable = 'Content 3' cursor.execute('''INSERT INTO posts(title, content) VALUES(?,?)''', (title_variable, content_variable)) db.commit() لا تنس أن تقوم باستدعاء الدّالة commit لتأكيد العمليّة. إذا قُمت بتنفيذ الشّيفرة أعلاه، وقُمت بعدها بتنفيذ الدّالة get_posts التي أنشأناها سابقا، ستتمكّن من رؤية القيمتين Title 3 و Content 3 كعنصرين من قائمة المقالات. لنضع هذه الشّيفرة في دالة باسم create لإضافتها إلى الوحدة manage_db، ستقبل الدّالة مُعاملين، مُعامل للعنوان، ومُعامل آخر لمُحتوى المقال. def create(title, content): db = sqlite3.connect('DB_PATH') cursor = db.cursor() cursor.execute('''INSERT INTO posts(title, content) VALUES(?,?)''', (title, content)) db.commit() الحصول على القيم وتمريرها إلى القالب بعد أن أنشأنا وحدة تحتوي على أربعة دوال تؤدّي أربعة أوامر أساسيّة: get_posts: الحصول على المقالات على شكل قائمة من المجموعات يُمكن الدّوران حولها get_post_by_id: الحصول على عنوان ومُحتوى مقال حسب رقم مُعرّفه delete: حذف مقال create: إنشاء مقال جديد إذا اطّلعت على الدّرسين السّابقين، ستعرف كيفيّة الحصول على قائمة المقالات وكيفيّة تقديمها في ملفّ HTML دون قراءة الجزء الموالي، لذا فمن الأفضل أن تُحاول ذلك الآن، وعد إلى هنا إذا واجهتك أية مشاكل. مبدأ التطبيق سيحتوي التّطبيق على 4 موجّهات: موجّه الصّفحة الرّئيسية / موجّه إضافة المقال create/ موجّه صفحة المقال الواحد <post/<post_id/ موجّه حذف المقال <delete/<post_id/ موجها إضافة المقال وحذفه لن يقدّما صفحة HTML بل سيُنفّذان دالّة وبعدها سيعيدان التّوجيه إلى الصّفحة الرّئيسيّة مباشرة. الصفحة الرئيسية ستحتوي الصّفحة الرّئيسية على عناوين ومحتويات المقالات لذا سنستخدم الدّالة get_posts من الوحدة manage_db في المُوجّه الرّئيسي ما يعني بأنّنا يجب علينا استدعاء الوحدة، كما سنُقدّم المقالات في ملفّ HTML باسم index.html. في ملّف app.py ضع ما يلي: # -*- coding:utf8 -*- from flask import Flask, render_template import manage_db app = Flask(__name__) # Home Page @app.route("/") def home(): posts = manage_db.get_posts() return render_template('index.html', posts = posts) if __name__ == "__main__": app.run(debug=True) لاحظ بأنّنا استدعينا الدّالة get_posts وأسندنا قيمتها إلى المُتغيّر posts وبعدها نُقدّم الملفّ index.html مع تمرير المُتغيّر posts. بما أنّ المُتغيّر الذي مرّرناه عبارة عن قائمة سنقوم بالدوران حول هذه القائمة والوصول إلى كل عنصر في المجموعة على حدة. الجزء المسؤول عن عرض المقالات في ملفّ index.html: {% for post in posts %} <a href="post/{{ post[0] }}"> <h2> {{ post[1] }} </h2> </a> <a href="delete/{{ post[0] }}"><span class="delete">حذف</span></a> <p> {{ post[2] }} </p> {% endfor %} الشّيفرة أعلاه هي الجزء المسؤول عن عرض المقالات فقط، وقد تجاهلت العناصر الأخرى التي لا تهمّنا مثل الشّعار والتّنسيق وغير ذلك. يُمكنك الحصول على ملفّ index.html كاملا من على Github بعد حلقة For سنحصل على مجموعة بثلاثة عناصر، العنصر الأول عبارة عن رقم مُعرّف المقال، وسنستخدمه لوضع رابطين للمقال، رابط عرض المقال ورابط حذفه، ما يعني بأنّنا نستطيع الوصول مثلا إلى المقال الأول كالتّالي: post/{{ post[0] }} => http://127.0.0.1:5000/post/1 ويُمكن حذفه بالرّابط التّالي: delete/{{ post[0] }} => http://127.0.0.1:5000/delete/1 الرّوابط لن تعمل حاليّا لأنّنا لم ننشئ المُوجّهات بعد. سيُعرض عنوان المقال داخل وسم h2 بالسّطر التّالي: <h2> {{ post[1] }} </h2> سيُعرض مُحتوى المقال داخل وسم p بالسّطر التّالي: <p> {{ post[2] }} </p> صفحة عرض المقال لعرض المقال الواحد، سنستخدم ملفّ HTML آخر وسنسمّيه post.html، أمّا الموجّه المسؤول عن تقديم هذا المقال فسيكون كالتّالي: موجّه post في ملفّ app.py: # Single Post Page @app.route("/post/<post_id>") def post(post_id): post = manage_db.get_post_by_id(post_id) return render_template('post.html', post = post) الشّيفرة أعلاه عبارة عن مُوجّه باسم post يقبل مُعاملا post_id لنتمكّن من تمريره كمُعرّف للمقال للدّالة get_post_by_id من الوحدة manage_db. بعدها نقوم باستدعاء الدّالة للحصول على بيانات المقال على شكل مجموعة يُمكننا أن نصل إلى عناصرها كالتّالي: post[0] # عنوان المقال post[1] # المحتوى صفحة post.html: <div class="main"> <h2> {{ post[0] }} </h2> <p> {{ post[1] }} </p> </div> <a href="{{ url_for('home') }}" class="back_to_home">عُد إلى الصّفحة الرّئيسيّة</a> في الشّيفرة أعلاه، نقوم بعرض عنوان المقال داخل وسم h2 ونقوم بعرض المُحتوى داخل وسم p. السّطر الأخير عبارة عن رابط لتمكين الزّائر من العودة إلى الصّفحة الرّئيسيّة و home اسم الدّالة المسؤولة عن تقديم الصّفحة الرّئيسية (الموجودة مُباشرة بعد الموجّه /). # Home Page @app.route("/") def home(): ... ملحوظة: نستطيع استخدام الدّالة url_for لتوليد روابط الموجّهات، وذلك بوضع اسم الدّالة كمعامل. مثال: لنفرض بأنّ لدينا مُوجّها باسم hello ودالة باسم hello_page، سنتمكّن من إنشاء رابط إلى الموجّه hello كالتّالي: <a href="{{ url_for('hello_page') }}">Link to Hello Page</a> يُمكن كذلك وضع عنوان المقال كعنوان للصّفحة داخل وسم title: <title>{{ post[0] }}</title> حذف مقال طريقة حذف المقال شبيهة بطريقة عرضه، الاختلاف هنا هو أنّنا سنستخدم الدّالة redirect لإعادة توجيه المُستخدم إلى الصّفحة الرّئيسية مُباشرة بعد حذف المقال. لاستخدام الدّالة redirect سيتوجّب علينا استيرادها من وحدة Flask في بداية الملفّ app.py. سنحتاج كذلك إلى الدّالة url_for للتوجيه إلى الرّابط الصّحيح. from flask import Flask, render_template, redirect, url_for موجّه delete سيقبل معاملا باسم post_id لتمريره إلى الدّالة delete من الوحدة manage_db لحذف المقال الذي يحمل رقم المعرّف المُمرّر. # Delete Post @app.route("/delete/<post_id>") def delete(post_id): manage_db.delete(post_id) return redirect(url_for('home')) لاحظ استخدام الدّالة redirect مُباشرة بعد حذف المقال، تقبل الدّالة مُعاملا بقيمة رّابط الصّفحة الرّئيسية والذي حصلنا عليه بالدّالة url_for، ما يعني بأنّنا نقوم بحذف المقال ثمّ توجيه المُستخدم مُباشرة إلى الصّفحة الرّئيسية. إنشاء مقال جديد تعرّفنا مُسبقا على طريقة الحصول على القيم من المستخدم بطريقة طلبات GET من عنوان URL كالآتي: /create?title=post1&content=content1 يُمكننا استخدام request للحصول على القيم كالتّالي: title = request.args.get('title') content = request.args.get('content') يُمكن استخدام هذه الطّريقة لإضافة مقال إلى قاعدة البيانات لكنّها ليست مُجديّة في هذه الحالة، لأنّنا نرغب بأن نُتيح للمُستخدم إرسال بيانات دون تعديل عنوان URL كما يجب علينا أن نُسهّل المأموريّة على المُستخدم العادي. لكي نحصل على العنوان والمُحتوى بطريقة أفضل، سنستخدم نماذج HTML أو HTML Forms، وسنستخدم طريقة POST عوضا عن GET. سنضع النّماذج في ملفّ index.html مُباشرة تحت الجزء المسؤول عن عرض المقالات. <h4>أضف مقالا</h4> <form action="{{ url_for('create') }}" method="POST"> <input class="input" type="text" name="title" placeholder="عنوان المقال"/> <br> <textarea name="content" class="input" rows="10" placeholder="مُحتوى المقال"></textarea> <br> <input type="submit" value="أضف" /> </form> في الوسم form نضع رابط الموجّه create داخل الصّفة action لنُخبر المُتصفّح بأنّ البيانات التّي سيُرسلها المُستخدم يجب أن تذهب إلى موجّه إضافة مقال جديد create. بعدها نُخصّص طريقة إرسال البيانات بوضع كلمة POST داخل الصّفة method. بعد ذلك ننشئ حقلا لعنوان المقال باسم title وحقل نصّ باسم content وبعدها نضيف زرّا لتأكيد الإرسال. بعد أن تملأ النموذج وتضغط على زر "أضف" سيُرسل المُتصفّح البيانات إلى الخادوم وسنتمكّن من الحصول عليها في المُوجّه create عبر الوحدة request، ما يعني بأنّنا سنحتاج إلى استدعاءها في بداية الملف. from flask import Flask, render_template, redirect, url_for, request سننشئ المُوجّه create مع تمرير مُعامل آخر باسم methods يحتوي على قائمة بعنصرين يُمثّلان الطريقتين GET وPOST لأنّ الإعداد الافتراضي هو GET فقط، نضع هذا العامل لكي نتمكّن من استقبال البيانات. @app.route("/create", methods=['GET', 'POST']) بعدها سنتمكّن من الحصول على البيانات وإدخالها إلى قاعدة البيانات كالتّالي: if request.method == 'POST': title = request.form['title'] # الحصول على عنوان المقال content = request.form['content'] # الحصول على مُحتوى المقال manage_db.create(title, content) # إدخال القيم إلى قاعدة البيانات لاحظ بأنّنا نضع شرطا للتأكّد من أن الطلب الذي يرسله المُتصفح من نوع POST. بعدها نحصل على القيم التي أدخلها المُستخدم في النّموذج الموجود بملفّ index.html عبر القاموس form المُتواجد داخل الوحدة request. وكما فعلنا مع الموجّه delete سنقوم بإعادة توجيه المُستخدم إلى الصّفحة الرّئيسية. return redirect(url_for('home')) الموجّه create كاملا: # Create Post Page @app.route("/create", methods=['GET', 'POST']) def create(): if request.method == 'POST': title = request.form['title'] content = request.form['content'] manage_db.create(title, content) return redirect(url_for('home')) أصبح التّطبيق كاملا الآن ويُمكنك مُشاركته مع العالم. يُمكنك إضافة تنسيق css خاصّ بك أو تحميل الملفّات الكاملة للتّطبيق من Github وإضافة ملفّ style.css إلى التّطبيق الذي أنشأته (يُمكنك كذلك تعديله). إذا كان لديك سؤال حول هذا الدّرس، يُمكنك وضعه في قسم الأسئلة والأجوبة. ختاما تعرّفنا على طريقة بناء تطبيق يتفاعل مع المُستخدم ويترك له حريّة الوصول إلى قاعدة البيانات، لكنك تُلاحظ بأنّ الحماية معدومة في التّطبيق، إذ يُمكن لأي شخص أن يحذف جميع المقالات دون أي حاجز (ككلمة مرور مثلا). سنتعلّم في الدّرس القادم على كيفيّة حماية التّطبيق وإتاحة الوصول إلى قاعدة البيانات لمُستخدم واحد فقط، بحيث يُسجّل دخوله إذا أراد حذف أو إضافة مقال، أمّا بقيّة المُستخدمين فلهم إمكانيّة القراءة فقط.1 نقطة
-
عملت ككاتبة مُستقلة طيلة العشرين سنة الماضية، صادفت خلالها العديد من الأفكار الخاطئة التي يكثر تداولها حول العمل ككاتب مُستقل والتي قد تُصادفنا جميعا ما بين الحين والآخر. فيما يلي أسوأ هذه التصورات على الإطلاق وكيفية تصحيحها وتجاوزها: 1. اعمل بلا مقابل حاليا وستحصل على ما تستحقه لاحقا هل سبق وأن قال لك عميل مُحتمل: "نحن نملك ملايين القراء والعمل معنا فرصة رائعة لتصبح معروفًا". لست أنفي أن الحصول على شهرة في بداياتك مع العمل الحر ليس بالأمر الجيّد أو أنه لا يمكن أن نضحي من أجله، حيث أنه من المُحتمل جدًا أن يُساعدك ذلك لاحقًا في مسارك المهني، لكن لو فكّرت في الأمر لبرهة لتساءلت كيف يُمكن لموقع بهذه الشّهرة أن لا يدفع لي؟ كن على يقين أنهم لا يأبهون كثيرًا لك وإنما يحاولون فقط تقليل مصاريفهم فقط. الحل تطوّع بالكتابة الحرة للمؤسسات المحلية غير الربحية فهي وسيلة مثالية لاكتساب الخبرة والممارسة و لها مردود إيجابي على مستقبلك المهني وزيادة دخلك، كما أنك ستشعر بالفخر والتقدير لذاتك ولما قدمته من عمل تطوعي. 2. تحتاج لمهارة لغوية ونحوية متميزة يمكنني القول من خلال خبرتي الواسعة في التحرير والكتابة أن العديد من الكُتّاب يقعون في كثير من الأخطاء النحوية واللغوية، كما أن مدى إتقان اللغة وتجويدها أو ضعفها وخاصة اللغات الأجنبية أمر يتوقّف على احتياجات العمل ومتطلبات العميل، فمثلا التدوين والكتابة للشركات تحتاج مهارة لغوية ونحوية أكثر دقة وحرفية من الكتابة للأفراد فهم يعتمدون عليك كليةً في الصياغة وقد لا يتوافر لديهم المُراجع اللغوي، كما أن أي خطأ نحوى أوإملائي على موقع أي مؤسسة أو شركة ما قد تكون له عواقب وخيمة. أما إذا كنت مدوّنا أو محرّرا لمقالات في الصحف والمجلات ، فعلى الأرجح سيُعرض عملك على المُدقّق اللغوي والذي يملك مهارة تصيّد الأخطاء والعيوب فيقوم بتصحيحها وتعديلها حتى وإن كان العمل مستوفيًا كل عناصر البحث، منظمًا بشكل جيد،جذابًا ومشوّقًا ، بالطبع هذا لا يمنعك من القيام بواجبك على أكمل وجه في الكتابة والمراجعة لتترك انطباعا جيّدا لدى العميل ، فقط تذكر أن الأخطاء الإملائية الشاذة والضعف النحوي يمكن التسامح فيه في حال كان العمل متميزا. الحل بإمكانك استخدام المُدقّقات الإملائية المُتوفّرة على حزمة أوفيس المكتبية فهي كفيلة بتصيّد أغلب الأخطاء التي سترد في مقالاتك. أما إذا كنت تستخدم حزمة ليبر أوفيس فعليك بمُدقق "آية سبل". 3. تحتاج خبرة طويلة للعمل في مجال الكتابة الحرة من أكثر الأفكار الخاطئة شيوعا، فليست بالخبرة وحدها تحصل على فرصة العمل وخصوصا في مجال التدوين والكتابة حيث أن سمعتك الطيّبة وأفكارك وكتاباتك هي الأساس في توظيفك، كما أن باستطاعتك صقل هذه الخبرة وتنميتها عن طريق التدوين الاستضافي. الحل ما تحتاج فعلّا تعلّمه هو طريقة تقديم عروض جيّدة للعملاء. كما تحتاج أن تستهدف في بحثك المجلات، المدونات والصحف التي يستخدم الكُتَّاب فيها نمطًا مماثلًا لأسلوبك وطريقتك وتتشاركون نفس الاهتمامات والأفكار، تعلّم من هؤلاء الكُتاب والمدوِّنين كيفية تنظيم المواضيع وتحليل المقالات. 4. تحتاج مؤهلات صحفية في الواقع أنا لا أملك مثل هذه المؤهلات ولم يسألني أحدهم من قبل عنها ،ولكن يبدو أن السبب وراء شيوع هذه الفكرة هي إعلانات وظائف الدوام الكامل التي ما زالت تشترط هذه المؤهلات للحصول على الوظيفة. الحل إذا نزلنا لأرض الواقع سنجد أن ما تهتم به حقّا سواء المدونات أو الصحف والمجلات وتبحث عنه هو مُستقل مبدع لديه أفكارًا جديدة للمقالات ويستطيع ترجمتها إلى مقالات في وقتها المحدد، وهذا فقط ما يلفت نظرهم ويجذب اهتمامهم حتى لو افترضنا أن مجال تخصّصك لا يمتّ للصحافة بأيّة صِلة. 5. تحتاج معرفة كل ما يخص الـ SEO هي فكرة خاطئة ووثيقة الصلة في الأساس بالكتابة على الإنترنت في المدوّنات والمواقع الإلكترونية ،حيث يظنّ الجميع أن العمل على الإنترنت يحتاج خبرة في مجال SEO وهذا ليس صحيحا. الحل إذا كنت تعمل على موقع إلكتروني لشركة ما، تحدث مع عميلك عن منتجاته والخدمات التي يقدمها ومن خلال مثل هذه المناقشات ستُلم بالكلمات المفتاحية اللازمة للعمل. كل ما تحتاجه للنجاح والتميز في هذا المجال هو استخدام هذه الكلمات بحرفية وحرص بجانب أسلوبك الإبداعي في الكتابة. لست بحاجة أن تُقحم هذه الكلمات المفتاحية في كل سطر وبين الكلمة والأخرى وإلا سيخرج العمل ركيكًا وليس على المستوى المطلوب، عمومًا يمكنك معرفة أساسيات الـSEO بقليل من البحث على الإنترنت واستخدامها في موضوعاتك لتصبح أكثر جاذبية للقراء والمعلنين على حدٍّ سواء وسيقدر لك العملاء هذه الخدمة حتى مع وجود خبراء مختصين بتحسين المواقع الإلكترونية نظير مقابل مادي. 6. يجب أن تكون متاحا 24 ساعة على مدار اليوم يعني ذلك أن تكون مرهقًا ومستهلكًا طوال الوقت وتتوتّر علاقتك بأهلك وبكل من حولك والأسوأ أنه لا يمكنك أن تقدم للعميل عملًا مميزًا وأنت في هذه الحالة المُزرية. أنا شخصيا وقعت ضحية هذه الفكرة أثناء عملي مع عميلي الأول فهي كانت دائمة السفر لتايوان وترسل لي فاكسات العمل الساعة الثالثة صباحا متوقعةً منى الردّ على ملاحظاتها في التوّ واللحظة لدرجة أني وضعت جهاز الفاكس في غرفة النوم. ومما لا يثير الدهشة أن صفقة العمل بيننا لم تنتهِ على ما يُرام. الحل حدّد وقتًا مناسبًا لعملك ولا تعطي للعميل الانطباع أنك متاح ومستعد في أي وقت منعًا لوقوع المشاكل والأزمات بينكما، حدّد أوقات العمل المناسب لك والتزم بها إلا في حالات الظروف الطارئة ،أما إذا أصرّ العميل على العمل في أوقات غير منطقية تحدث معه في الأمر بشكل جدِّي وإذا استمر هذا الوضع ابدأ في البحث عن عميل آخر. 7. تنازل عن فكرتك في حال لم تنل إعجاب العميل من الطبيعي أن لا تكون فكرتك دائما محل إعجاب الآخرين وقد يعتقد العميل أحيانا أنها موضوع غير مناسب للمقال، عليك أن تستوعب أن هذا ليس هو نهاية المطاف ولا حتى نهاية هذا المقال المرتقب. الحل عندما يرفض أحد العملاء فكرتك فهذا لا يعني بالضرورة ألاّ تعجب الآخرين بل هي تستحق منك أن تعمل عليها وتطوّر منها قليلا لتصبح أكثر جاذبية. اطلب تقييم فكرتك ومعرفة ردود الفعل حولها من العملاء، سيستجيب البعض منهم لا جميعهم، تحتاج أن تعرف لماذا لم تنجح فكرتك وما هي الموضوعات التي تم تغطيتها مؤخرًا وما إذا كانت هذه الفكرة خارج حيّز اهتمام العملاء مما يعني أن بحثك لم يكن كافيا أم أن طريقة عرضك للفكرة لم تكن جيدة وغير مقنعة. وعلى الرغم من الإحباط الذي قد يصيبك وقسوة هذا الشعور إلا أن كل الصعوبات التي تكتشفها وتمرّ بها ستكون مثمرة ومفيدة لك في المستقبل. 8. قل نعم دائما للعميل مقولة أن العميل دائما على حق ليست بمقولةٍ صحيحة، ففي بعض الأحيان يطرح العميل أفكارًا غير مناسبة على الإطلاق وأحيانا يطلب منك مهمة معقّدة بلا تفاصيل أو ملاحظات تُذكر، والبعض منهم يتّسم باللامنطقية بكل معنى الكلمة. الحل يكمن الحل في الصدق. كن على أتمّ الاستعداد لتناقش وتدافع عن رؤيتك للفكرة ولماذا ترفضها وكيف ترى أنها غير مناسبة، تأكّد أنك تملك الحقائق الكافية لتدعّم رأيك لتكون مقنعا ولا ترفض الفكرة بدون إبداء أسباب منطقية. هذه المواقف وغيرها ستكشفك أمام نفسك ودوافعها الحقيقية فقد يكون سبب الرفض صعوبات في العمل أواعتبارات شخصية مثل التردد وعدم الحماسة لهذا المشروع. في بعض الأحيان عليك أن تعرف كيف تقول لا حتى وإن كنت ستخسر هذا العميل، إلا إذا كنت تخشى المواجهة وتحتاج بشدة لهذا العمل ففي هذه الحالة حاول أن توائم بين متطلبات العميل والوضع الذي يناسبك. استفد من تجربتي ولا تكرر نفس خطئي و قل لا. خلاصة هذه هي أهم الأفكار السلبية التي تحيط بمجال العمل الحر وأكثرها عقبات صغيرة يمكن تجاوزها بسهولة: العمل بلا مقابل لدى العميل المعروف. إتقان المهارة النحوية والإملائية. المؤهلات الصحفية. خبير في محركات البحث SEO. العمل 24 ساعة على مدار الأسبوع24/7. تنازل عن فكرتك الجيدة. قل نعم دائما لعملاءك. التخلص من هذه الأفكار والخرافات ستجعل منك مُستقلا سعيدًا ومستمتعًا بعمله. ترجمة -وبتصرّف- للمقال 8Myths About Freelance Writing – And How to Bust Them لصاحبته LIS STEDMAN.1 نقطة