仕事マッチアプリTASK MEを公開

Python×DjangoでマッチングアプリTASK MEを制作しています。

主な機能

・お仕事登録
・お仕事リスト検索
・通知機能
・マイプロフィール登録
・お支払い機能
・DM送受信


テーブル定義


層の構成

 

大きく分けて
・joblist
・main
・users
のこれらのアプリを作成、この先からDM機能、マイプロフィール登録、お支払い機能を作成する。

基本的に遷移順に作っていきます。
メイン画面→画面表示→情報を追加する画面→情報を編集する画面
サブ機能のメイン画面→サブ機能を編集する画面
API画面(DM機能やお支払い機能)など


メインである、「joblist」アプリ=仕事のリスト画面から作成しました。
ここはclassのTemplateを使用しています。
class内で変数の指定をしていけば簡単に実装できるのですっきりして管理がしやすいです。
※追加の際はクラスのメソッドにオーバーライドをしていけば追加が可能です。

joblist.views.py


from django.db.models.query import QuerySet
from django.views.generic import ListView,CreateView,UpdateView,DeleteView
from .models import JobPost
from django.urls import reverse_lazy
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin

user = get_user_model()

#----仕事一覧ページ------
class JobPostView(ListView):
    model = JobPost
    template_name = "job_post_list.html"

    def get_queryset(self, **kwargs):
        queryset = super().get_queryset(**kwargs) # Article.objects.all() と同じ結果
        # GETリクエストパラメータにkeywordがあれば、それでフィルタする
        keyword = self.request.GET.get('keyword')
        if (keyword):
            queryset = queryset.filter(job_detail__icontains=keyword)

        return queryset
    
class JobRegistView(CreateView,LoginRequiredMixin):
    model = JobPost
    template_name = "job_regist.html"
    success_url = reverse_lazy("joblist:job_post_list")
    fields = ['job_title','job_detail']
    
    def form_valid(self, form):
            # ログインしているユーザーを取得し、それを紐づける
            form.instance.user = self.request.user
            form.instance.user_name = self.request.user.username
            return super().form_valid(form)

class JobUpdateView(UpdateView,LoginRequiredMixin):
    model = JobPost
    template_name = "job_update.html"
    success_url = reverse_lazy("joblist:job_post_list")
    fields = ['job_title','job_detail']
    pk_url_kwarg = 'pk'  # プライマリキーの名前を指定


joblist.urls.py

from django.urls import path
from . import views

app_name = "joblist"

urlpatterns = [
    path('',views.JobPostView.as_view(),name='job_post_list'),
    path('<int:pk>/update/',views.JobUpdateView.as_view(),name='job_update'),
    path('job_regist/',views.JobRegistView.as_view(),name='job_regist'),
]

index.html



{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>サイドメニュー</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
</head>
<body>
    <div class="container">
        <!-- サイドメニュー -->
        <div class="side-menu">
            <ul>
                <li><a href="/job_post_list/">仕事リスト画面</a></li>
                <li><a href="/company/">会社説明</a></li>
                <li><a href="/notifications/">通知画面</a></li>
                <li><a href="/job_post_list/job_regist/">仕事登録画面</a></li>
                <li><a href="/profile/">マイプロフィール登録画面</a></li>
                <li><a href="/direct_mail/">DM画面</a></li>

            </ul>
        </div>

        <!-- コンテンツエリア -->
        <div class="content">
            <h1>こんにちは、{{user}}さん</h1>
            <p>ここにコンテンツが表示されます。</p>
        </div>
    </div>
</body>
</html>


main.views.py


from django.http import HttpResponse
from django.views.generic import TemplateView
from users.models import User


#----Indexページ------
class IndexView(TemplateView):
    model = User
    template_name = "index.html"


usersモデルは、既存のauth userは使わない。
abstractBaseuserを使用し、拡張して使用する。

users.models.py

from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.core.mail import send_mail
from django.utils import timezone
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils.translation import gettext_lazy as _

class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, username, email, password, **extra_fields):
        if not email:
            raise ValueError('Emailを入力して下さい')
        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self.db)
        return user
    def create_user(self, username, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, username, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        if extra_fields.get('is_staff') is not True:
            raise ValueError('is_staff=Trueである必要があります。')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('is_superuser=Trueである必要があります。')
        return self._create_user(username, email, password, **extra_fields)
    
class User(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(_("username"), max_length=50, validators=[username_validator], blank=True)
    email = models.EmailField(_("email_address"), unique=True)
    is_staff = models.BooleanField(_("staff status"), default=False)
    is_active = models.BooleanField(_("active"), default=True)
    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)

    objects = UserManager()
    USERNAME_FIELD = "email"
    EMAIL_FIELD = "email"
    REQUIRED_FIELDS = ['username']

    class Meta:
        verbose_name = _("user")
        verbose_name_plural = _("users")

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)


{% extends 'base.html' %}

{% block title %}仕事リスト画面{% endblock %}

{% block page_title %}
  <div class="page-title">仕事リスト画面</div>
{% endblock %}

{% block content %}
  <div class="job-list">
    <a href="/job_post_list/job_regist/">仕事を登録する</a></li>
    
    <!-- 検索ボックス -->
    <form method="get">
      <input type="text" name="keyword" placeholder="キーワードを入力">
      <button type="submit">検索</button>
    </form>
    <p class="section-title">仕事募集一覧</p>


    {% if object_list %}
    {% for post in object_list %}
    <!-- サーチ結果がある場合の表示 -->
        <!-- カードスタイルのカード -->
            <div class="job-card">
            <p class="job-title">
              {{ post.job_title }}</p>
            <div class="separator-line"></div>
            <p>{{ post.user_name }}</p>
            <div class="separator-line"></div>
            <p>{{ post.job_detail }}</p>
            <div class="separator-line"></div>
            <p>{{ post.created_at }}</p>
            <div class="separator-line"></div>
            {% if user.is_authenticated and user == post.user %}
            <p><a class='btn btn-primary' href="{% url 'joblist:job_update' pk=post.post_id %}">編集する</a></p>
            {% else %}
            <p>  </p>
            {% endif %}
          </div>
    {% endfor %}
  {% else %}
    <!-- 検索結果がない場合の表示 -->
    <p>キーワードに対する検索結果はありません。</p>
{% endif %}
</div>
{% endblock %}

簡易的な画面表示

メイン画面


・ログインユーザーで「編集する」リンク活性。
・仕事の検索が可能

仕事リスト画面


DM画面実装


DM画面

左側に送信者、右側に受信者を表示している。

ログインユーザーを受信者、送信者を相手に置き会話を構成する。
まずInboxで自分との会話を表示して1対1の絞り込みを行うようにする。
そのあとでその人との会話を絞り込む。

from django.views.generic import ListView
from .models import DirectMessage
from django.contrib.auth import get_user_model
from django.views.generic import FormView, ListView
from django.shortcuts import redirect
from .forms import DirectMessageForm

user = get_user_model()

class InboxView(ListView):
    template_name = 'inbox.html'
    context_object_name = 'chat_partners'

    def get_queryset(self):
        # ログインユーザーが送信したメッセージを取得し、送信相手を特定する
        sent_messages = DirectMessage.objects.filter(sender=self.request.user)
        chat_partners = {}
        for message in sent_messages:
            chat_partners[message.recipient] = message.timestamp

        # テンプレートに渡すコンテキストに送信相手との最新のメッセージ履歴を追加する
        return sorted(chat_partners.items(), key=lambda x: x[1], reverse=True)
ト
 

class ChatView(ListView):
    template_name = 'chat.html'
    context_object_name = 'messages'

    def get_queryset(self):
        # ユーザーが送信したメッセージと受信したメッセージを取得
        sent_messages = DirectMessage.objects.filter(sender=self.request.user)
        received_messages = DirectMessage.objects.filter(recipient=self.request.user)
        # メッセージを日付でソートして結合
        all_messages = list(sent_messages) + list(received_messages)
        all_messages.sort(key=lambda x: x.timestamp)

       # チャット相手を特定する
        chat_partner = None
        if sent_messages.exists():
            chat_partner = sent_messages.first().recipient
        elif received_messages.exists():
            chat_partner = received_messages.first().sender
          
        # テンプレートに渡すコンテキストにチャット相手を追加する
        self.extra_context = {'chat_partner': chat_partner}
        

        return all_messages


以後、少しずつ追記していきます。


ご覧いただきありがとうございました。 サポートしていただいたお金は開発費にかけさせていただきます。