본문 바로가기

카테고리 없음

Neo4j 와 Django 연동 및 예제

Neo4j

Neo4j은 NoSQL 데이터베이스의 하나로인 그래프 데이터베이스로, 그래프 데이터 베이스 중에서 전세계적으로도 점유율 1위를 하고 있는 데이터베이스이다. 그래프 기술은 2019년 가트너 유망 트랜드로도 선정된 만큼 그 잠재력은 무궁무진하다. Neo4j Graph 플랫폼은 오픈소스로 Neo4j Database에 그래프 접속을 할 수 있도록 도와주는 툴이다.


Neo4j 특징

  • 그래프 데이터 베이스
    • 연결된 데이터를 저장하고 검색 가능한 그래프 데이터베이스이다.
    • Neo4j 그래프 데이터베이스와 연동하여 객체 그래프 매핑 (Object-Graph Mapping, OGM)을 제공한다.
  • 퀴리 언어
    • Neo4j는 Cypher라는 선언형 그래프 퀴리 언어 사용한다.
    • Cypher 직관적으로 이해하고 습득할 수 있으면 SQL보다 코드 양을 줄일 수 있다.
  • 유연한 스키마
    • Neo4j는 속성 그래프 모델이라고 불리는 모델링 기법을 기반으로 하며 자연에 가까운 형태로 데이터를 모델링할 수 있다.
  • 효율성
    • 데이터와 관계는 함께 저장되어 복잡성과 규모가 커짐에 따라 성능이 향상된다.
    • 서버 통합과 하드웨어의 매우 효율적인 사용이 가능하다.

Neo4j 단점

  • 국내에는 아직 널리 활용되지 않아 관련 자료가 제한적이다.
  • NoSQL 이여서 Django 와 neo4j의 데이터베이스가 직접적으로 연결되지 않는 문제점이 있다.

Neo4j 설치(mac os)

  1. Neo4j 공식 홈페이지 다운로드 들어가기

Neo4j Deployment Center

 

Neo4j Deployment Center

Enterprise-grade availability and security with scale-up and scale-out options. Run in your private cloud or public cloud infrastructure. Enterprise Edition includes Bloom, Graph Data Science Library and APOC procedures. Additional license keys may be requ

neo4j.com

자신의 기종에 맞는 걸 다운로드 받기

2. Project 생성 New 버튼을 누르고 Create project 만들기

3. Local DBMS 눌러주고 프로젝트가 만들어지면 이름을 정해주고 password를 작성하면 된다. password는 8자리로 만들어야 한다.

4. start 버튼을 누르면 neo4j browser 나온다. 이제부터 노드 생성하고 관계형 데이터 베이스를 만들면 된다


노드(Node)

  1. 노드 생성하기

노드는 생성이 되었지만 내용은 아무것도 없는 것을 확인할 수 있다.여러 개가 생성 되는 걸 확인할 수 있다. 하지만 내용은 아무것도 없다.

CREATE (노드1),(노드2); //소문자로 작성해도 상관없다. RETURN (n) RETURN //전체적으로 노드를 보여준다.
CREATE (노드 원하는 이름 작성) RETURN (n) RETURN //전체적으로 노드를 보여준다.

노드는 생성이 되었지만 내용은 아무것도 없는 것을 확인할 수 있다.

CREATE (노드1),(노드2); //소문자로 작성해도 상관없다.
RETURN (n) RETURN  //전체적으로 노드를 보여준다.

여러 개가 생성 되는 걸 확인할 수 있다. 하지만 내용은 아무것도 없다.

 

2. 라벨 생성하기

CREATE (node(이름):label(라벨이름):label2(라벨이름)...);
CREATE (node:Person:Job:Age)
//label은 한 개부터 여러 개 가능하다.

테이블에 들어가보면 라벨에 “Person”, “Job”, ”Age” 추가되어 있는 게 보인다.

 

3. 속성 생성하기

CREATE (node(이름):label(라벨이름){key1:value, key2:value2}
CREATE (User:Person{name:"ssojungg",hobby:"book" })
//label은 한 개부터 여러 개 가능하다.

“ssojungg”이라는 속성이 생성된 것을 확인할 수 있다. 테이블에서 보면 라벨은 Person에 속성에 name, hobby 추가 된 것을 확인할 수 있다.

관계(Relation)

  1. 관계 생성하기
CREATE (User1:Person{name:"ssojungg",hobby:"book" })
CREATE (User2:Person{name:"minmin",hobby:"movie"})
CREATE (User1)-[r:Best_Friend]->(User2)
RETURN User1,User2
//CREATE (node이름:label이름{속성 작성})


Django

Django

 

Django

The web framework for perfectionists with deadlines.

www.djangoproject.com

Django는 2005년부터 시작된 Python의 오픈 소스 웹 프레임워크이자 풀 스택 프레임워크이다. 유명 사이트 Instagram, Mozilla Firefox에서 Django를 이용해 만들었다. 파이썬을 기반으로 한 만큼 진입장벽이 낮다.


Django 특징

  • MTV 패턴을 사용
    • Model(DB에 저장되는 데이터), Template(유저에게 보여주는 UI), View(데이터 처리하고 Template에 데이터 전달)
  • ORM 기능 지원
    • 장고의 객체 관계 매핑(ORM) 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다.
    • 데이터베이스를 SQL문 없이 파이썬 언어를 통해 처리할 수 있으며, 모델에서 보면 데이터 베이스를 선언할때도 마찬가지로 SQL없이 데이터베이스를 만드는 것을 확인할 수 있다.
  • 보안성
    • 사용자 인증 시스템은 계정과 비밀번호를 안전하게 관리할 수 있는 방법을 제공한다.
    • SQL 인젝션, Cross-site scripting(XSS), Cross-site request(사이트 간 요청 위조), 클릭 재킹 등의 일반적인 보안 실수를 개발자가 피할 수 있게 도와준다.
  • 자동으로 구성되는 관리자 화면 제공
    • 로그인, 회원가입 인증등 라이브러리를 통해 간단히 구현이 가능하다.

Django 단점

  • 다른 프레임워크에 비해 확장성이 떨어진다.
  • 인터프리터 언어이기 때문에 생기는 문제점 속도와 실행될때까지 걸리지 않는 에러가 있다.

Django 설치

  1. 아나콘다 설치(mac os)
 

Free Download | Anaconda

Anaconda's open-source Distribution is the easiest way to perform Python/R data science and machine learning on a single machine.

www.anaconda.com

 

가상환경을 위해 아나콘다를 설치해 준다.

계속 누르면 완료하면

터미널에서 conda 라고 치면 설치가 완료되었는지 알 수 있다.

2. 가상환경 생성

conda create -n 가상환경 이름 python = 파이썬 버전

 

3.  활성화

conda activate <가상환경이름>

 

4.  장고 설치

pip install django


Docker 기본세팅

//파일 구조
RememberPlus
┣📦backend
┃┣ 📂backend
┃┃┣ 📂__pycache__
┃┃┣ 📜__init__.py
┃┃┣ 📜asgi.py
┃┃┣ 📜settings.py
┃┃┣ 📜urls.py
┃┃┗ 📜wsgi.py
┃┃┣ 📂neo_db
┃┃┣ 📜__init__.py
┃┃┣ 📜admin.py
┃┃┣ 📜apps.py
┃┃┣ 📜models.py
┃┃┣ 📜selializers.py
┃┃┣ 📜urls.py
┃┃┗ 📜views.py
┃┣ 📜.git
┃┣ 📜.gitmessage.txt
┃┣ 📜Dockerfile
┃┣ 📜db.sqlite3
┃┣ 📜manage.py
┃┗ 📜requirements.txt
┣ 📜docker-compose.yml
┗ 📜README.md

 

# RememberPlus/backend/Dockerfile
# 베이스 이미지 선택
FROM python:3.9

# 작업 디렉토리 설정
ENV PYTHONDONTWRITEBYTECODE 1 
ENV PYTHONUNBUFFERED 1 # Docker에서 로그를 실시간으로 확인하는 데 유용

# ARG 명령어는 Docker 빌드 과정 중에 값을 받을 수 있는 변수를 정의
# 변수들은 Docker 이미지를 빌드할 때 값을 할당받게 됨
ARG DJANGO_ALLOWED_HOSTS 
ARG DJANGO_SECRET_KEY
ARG DJANGO_CORS_ORIGIN_WHITELIST

# ARG에서 정의된 변수의 값을 ENV 환경 변수에 할당
# ENV 명령어로 설정된 환경 변수는 이미지 내부에서 사용
ENV DJANGO_ALLOWED_HOSTS $DJANGO_ALLOWED_HOSTS
ENV DJANGO_SECRET_KEY $DJANGO_SECRET_KEY
ENV DJANGO_CORS_ORIGIN_WHITELIST $DJANGO_CORS_ORIGIN_WHITELIST

# WORKDID 명령어는 Docker 컨테이너 내의 작업 디렉토리 설정
# ENV 명령어로 설정된 환경 변수는 이미지 내부에서 사용
WORKDIR /backend #자신의 맞게 경로 지정

# requirements.txt 파일을 컨테이너 내 '/backend/' 디렉토리로 복사
COPY requirements.txt /backend/

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

# requirements.txt 파일에 명시된 Python 패키지를 설치
RUN pip install Pillow #이미지 처리하기 위해 필요(Neo4j 필요없음)
RUN pip install neo4j-driver #neo4j를 사용하기 위해서 필요
RUN pip install gunicorn # 구니콘이여서 지금은 필요없음
COPY . /backend/

Django 와 Docker 연동

# RememberPlus/docker-compose.yml
django:
    build:    #빌드하기 위한 설정을 시작
      context: ./backend   #이미지를 빌드하기 위한 컨텍스트 디렉토리. Dockerfile이 위치한 디렉토리 의미
      args: #Dockerfile에 있는 ARG 변수들의 값을 설정
        DJANGO_ALLOWED_HOSTS: “*” # 환경 변수에 값을 할당 
        DJANGO_SECRET_KEY: “*” # "*" -> 모든 권한 허용
        DJANGO_CORS_ORIGIN_WHITELIST: “*”  # 장고 환경변수들 설정 접속권한 허용
    container_name: container_django #container 이름 지정
    volumes: #데이터의 영속성을 보장하거나 코드 변경 시 컨테이너에 번영할 수 있음
      - ./backend/:/backend/ # ./backend/ 디렉토리를 컨테이너의 /backend/에 마운트
      - ./backend/static/:/backend/static/ 
		# ./backend/static/ 디렉토리를 컨테어너의 /backend/static/에 마운트
		# [호스트 시스템의 경로]:[컨테이너 내의 경로]
    expose:
      - 8000
		# 컨테이너의 8000포트를 expose. 접근 가능함
    ports:
      - "8000:8000"
		# 호스트의 8000 포트를 컨테이너의 8000 포트에 바인딩
    depends_on:
      - neo4j
        # django 서비스는 neo4j 서비스에 의존한다
				# neo4j 서비스 먼저 시작
    command:
			#구니콘이므로 필요없음
      - gunicorn
      - "--bind"
      - "0:8000"
      - "backend.wsgi:application"
  • 초록색깔 버튼을 누루면 부분적으로 docker와 연동되어서 작동하는 것을 확인할 수 있다.

  • 로그를 파이참에서 볼 수 있어 틀린 부분을 쉽게 찾아볼 수 있다.

Neo4j 와 Docker 연동

# RememberPlus/docker-compose.yml
version: '3' #버전
services:
  neo4j:
    image: neo4j:latest 
		# Docker 이미지는 neo4j의 최신 버전
    container_name: container_neo4j 
		# 컨테이너 이름을 지정
    ports:
      - "7689:7687" 
		# 7687 포트는 Neo4j 프로토콜을 위한 기본 포트
    environment: 
		# 컨테이너 내부에서 사용할 환결 변수 설정
      - NEO4J_AUTH=neo4j/123412341234 
				#유저/비밀번호        
      - NEO4J_dbms_security_auth__minimum__password__length=12  
			#패스워드 최대 길이 12
      - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
			# 라이선스 동의 나태나는 환경 변수. 
			# yes -> 라이선스에 동의함
    volumes:

Neo4j 와 Django 연동

# Remember/backend/backend/settings.py
ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django_neomodel', # neo4j연동에 필요
    'rest_framework', #장고 연동을 위한 필요
    'neo_db.apps.Neo_dbConfig', 
    'corsheaders',
]

# # Neo4j 데이터베이스 설정
# NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:123412341234@container_neo4j:7689')
DATABASE_URL = "bolt://user:password@container_neo4j:7687"

NEO4J_BOLT_URL = 'bolt://container_neo4j:7687'
NEO4J_USERNAME = 'neo4j'
NEO4J_PASSWORD = '123412341234'
  • Docker 와 연동이 되었다는 걸 확인할 수 있다.

예제

neo4j browser 이용

1. HAVE 관계

//User 와 Card 라벨을 만들어 HAVE 관계로 연결해줌
CREATE (u:User {uid:'ssojungg11' , name:'ssojungg' , email:'ssojungg@gmail.com'})
CREATE (c:Card {uid:'ssojungg11' ,name:'소정' , email:'ssss@gmail.com'})
CREATE (u)-[h:HAVE]->(c)
RETURN u,c,h
//CREATE문으로 생성해주기

2. RELATION 관계

//이미 있는 User 2개의 노드를 RELATIONA 관계로 연결해줌
MATCH (u1:User {email:'ssojungg@gmail.com'}),(u2:User {email:'minmin@gmail.com'})
CREATE (u1)-[r:RELATION {relation_name:'친구' , memo:'베스트_프랜드'}]->(u2)
RETURN u1,r,u2
//MATCH를 통해 이미 생성된 노드들을 찾고 연결해주기
//minmin 이라는 User를 만들고 했다고 가정함

 

Django를 통해 만들기

1. HAVE 관계

serlializers.py

# RememberPlus/backend/neo_db/serlializers.py
# (여기는 필수항목리아고 뜨는 json문에 대한 응답을 보여주는 항목들이라고 생각하시면 됩니다~ 아 노드의 들어가는 것들을 나열한 거라고 생각하세요!)
import datetime
import uuid
from rest_framework import serializers
import bcrypt
from neo4j import GraphDatabase, basic_auth

from backend import settings
from .models import USER, CARD, HAVE, RELATION  # models 모듈에서 USER, CARD, HAVE 클래스를 불러옵니다.

class UserRegisterSerializer(serializers.Serializer):
    user_uid = serializers.UUIDField(read_only=True)
    user_name = serializers.CharField(max_length=100)
    user_email = serializers.EmailField()
    password = serializers.CharField(max_length=50)
    user_phone = serializers.CharField(max_length=20, required=False)
    user_photo = serializers.ImageField(required=False, default='http://127.0.0.1:8000/static/person.png')
    is_user = serializers.BooleanField(read_only=True)
    created_at = serializers.DateTimeField(read_only=True)

    def validate(self, attrs):
        attrs['user_uid'] = str(uuid.uuid4()) #자동생성된 user_uid 값을 가짐

class CardSerializer(serializers.Serializer):
    card_uid = serializers.UUIDField(read_only=True)  # 추가
    card_name = serializers.CharField(max_length=100)
    card_email = serializers.EmailField()
    card_phone = serializers.CharField(max_length=20)
    card_intro = serializers.CharField(max_length=3000, allow_blank=True)
    card_photo = serializers.ImageField(required=False, default='http://127.0.0.1:8000/static/card.png')
    created_at = serializers.DateTimeField(read_only=True)
    update_at = serializers.DateTimeField(read_only=True)

    def validate(self, attrs):
        attrs['card_uid'] = str(uuid.uuid4())
        return attrs

class HAVESerializer(serializers.Serializer):
    have_uid = serializers.CharField()
    created_at = serializers.DateTimeField()
    updated_at = serializers.DateTimeField()

serlializers 정의 및 설명

  • 데이터 직렬화 및 역직렬화
    • client ↔ server 간의 데이터 교환을 위해 복잡한 데이터 타입을 JSON 형태로 변환한다.
  • 필드 속성 및 타입 정의
    • 각 필드의 데이터 타입 미 속성을 정의한다.
    • 이를 통해 데이터의 구조와 제약 조건을 명확히 지정할 수 있다.

➡️ 데이터를 외부와 교환하는 형식과 규칙을 정의

 


models.py

#RememberPlus/backend/neo_db/models.py
from neomodel import StructuredNode, StringProperty, BooleanProperty, DateProperty, UniqueIdProperty, RelationshipTo,
    RelationshipFrom, DateTimeProperty, StructuredRel

class HAVE(StructuredRel):
    uid = UniqueIdProperty() // UniqueIdProperty()  -> 고유한 식별자를 나타냄
    created_at = DateTimeProperty(default_now=True) -> 생성날짜 알려줌
    updated_at = DateTimeProperty(default_now=True) -> 업데이트 날짜 알려줌
 
class USER(StructuredNode):
    user_uid = StringProperty(required=False)  #고유한 식별자를 나타냄
    user_name = StringProperty(unique_index=True, required=True)
    user_email = StringProperty(unique_index=True, required=True)
    password = StringProperty(required=True)
    user_phone = StringProperty(unique_index=True)
    user_photo = StringProperty()
    is_user = BooleanProperty(default=True)
    created_at = DateProperty(auto_now_add=True)
    update_at = DateProperty(default_now=True)
    cards = RelationshipTo('CARD', 'HAVE', model=HAVE) 
		# CARD 노드와의 관계를 나타내며, 사용자가 가지고 있는 카드 정보와 연결
		# 관계의 타입은 'HAVE'이며, HAVE 모델을 사용
    relations = RelationshipTo('USER', 'RELATION', model=RELATION)  # Use this line only

class CARD(StructuredNode):
    card_uid = StringProperty(required=False) #추가
    card_name = StringProperty(unique_index=True, required=True)
    card_email = StringProperty(unique_index=True, required=True)
    card_phone = StringProperty(required=True)
    card_intro = StringProperty()
    card_photo = StringProperty(required=True)
    created_at = DateProperty(auto_now_add=True)
    update_at = DateProperty(default_now=True)
    owners = RelationshipFrom('USER', 'HAVE', model=HAVE) 
		# USER 노드와의 관계를 나타내며, 카드의 소유자 정보와 연결
	  # 이 관계의 역방향 타입은 'HAVE'이며, HAVE 모델을 사용

model 정의 및 설명

  • 구조체 및 관계 정의
    • StructuredNode 는 Neo4j 데이터베이스 노드를 표현하는 클래스이다. 이를 사용해 데이터베이스 내의 실제 노드와 매핑된다.
    • 관계를 정의함으로써, Neo4j의 그래프인 형태인 노드 간의 연결을 나타내며, 데이터 간의 관계성을 표현한다.
  • 필드 및 타입 설정
    • 각 노드의 저장될 데이터의 필드와 그 타입을 설정한다.
    • (Ex, ‘StringProperty’ → 문자열 데이터, ‘BooleanProperty’ → 블리언 데이터)
    • 필드에 특별한 제약 조건(Ex, required=False)이 필요한 경우 지정할 수 있음.
  • 데이터 기반 처리
    • 실제 데이터베이스의 데이터를 저장하거나 조회할 때 사용
    • 데이터베이스와 애플리케이션 간의 통신이 원활하게 이루어짐.
    • 데이터의 일관성과 정확성을 유지한다.

➡️ 데이터의 구조와 저장 방식을 정의

 


 

serlializers models 의 관계

  • Client → Server
    • API호출 시, Server는 이 요청을 받아 처리한다.
  • serlializers → models
    • serializers.py 에서 검증 및 변환된 데이터는 models.py 를 통해 Neo4j 데이터베이스에 저장되거나 조회된다.
  • Models → Neo4j Database
    • models.py 는 Neo4j 데이터베이스와의 직접적인 연결을 관리하며, 데이터베이스의 CRUD(생성, 조회, 업데이트, 삭재)을 수행한다

➡️ Client → Server → Serializers (역직렬화) → Models → Neo4j Database

Server → Client

  • Server → Client
    • 응답을 보냄.
  • models → serlializers
    • Models 를 통해 데이터베이스로부터 필요한 정보를 조회한다.
    • Serlializers 데이터를 직렬화 하여 JSON문 형식으로 변환한다.
    • 변환한된 데이터는 응답 본문을 포함되어 클라이언트에게 전송된다.

➡️ Server → Serializers (직렬화) → Client

 


#RememberPlus/backend/neo_db/views.py
#neo4j 연동
config.DATABASE_URL = settings.NEO4J_BOLT_URL
config.DATABASE_AUTH = (settings.NEO4J_USERNAME, settings.NEO4J_PASSWORD)

# Neo4j 드라이버 생성
driver = GraphDatabase.driver(config.DATABASE_URL, auth=basic_auth(*config.DATABASE_AUTH))

class RegisterView(views.APIView):
    def post(self, request):
		# self -> 현재 객체의 인스턴스를 참조합니다. 클래스 내에서 정의된 속성이나 메서드에 접근하기 위해 사용됩니다.
		# request -> 요청에 포함된 데이터, 메소드 타입 정보 포함한다.
		# POST 요청 처리
        serializer = UserRegisterSerializer(data=request.data)
				# UserRegisterSerializer -> serializer에 있는 이걸 쓸 거다
				# data=request.data -> 클라이언트로부터 받는 JSON 데이터를 포함하고 있다. UserRegisterSerlializer 에 전달하여 역직렬화 시작한다.
        if serializer.is_valid(): # 데이터 유효성 검사
            data = serializer.validated_data
# post 요청을 받은 사용장 등록 정보를 역직렬화하고, 데이터 유효성 검사, 이후 로직에 유효한 데이터 제공

            # 필수 항목 확인
            if 'user_email' not in data or 'password' not in data:
                return Response({"message": "이메일과 비밀번호는 필수로 입력해야 합니다.", "result": None},
                                status=status.HTTP_400_BAD_REQUEST)

            with driver.session() as session:
#session -> neo4j 데이터베이스 새로운 세션 시작
                # 전화번호 중복 확인
                result = session.run("MATCH (user:USER) WHERE user.phone = $user_phone RETURN user",
                                     {"user_phone": data['user_phone']})
                if result.single():
                    return Response({"message": "이미 존재하는 전화번호입니다.", "result": None}, status=status.HTTP_204_NO_CONTENT)
                # 이메일 중복 확인
                result = session.run("MATCH (user:User) WHERE user.email = $email RETURN user",
                                     {"email": data['user_email']})
                if result.single():
                    return Response({"message": "이미 존재하는 이메일입니다.", "result": None}, status=status.HTTP_204_NO_CONTENT)

                # 새로운 사용자 추가
                # 업데이트는 노드에 보이지 않음
                r = session.run("""
                    CREATE (user:User {
                        uid: $user_uid,
                        name: $user_name,
                        email: $user_email,
                        password: $password,
                        phone: $user_phone,
                        photo: $user_photo,
                        is_user: $is_user,
                        created_at: date($created_at)
                    })
                """, **data)

            return Response({
                "message": "회원가입 성공",
                "result": data
            }, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CardAddView(views.APIView):

    def post(self, request, user_uid):
# (self, request, user_uid) -> 함수의 매개변수이다.
# user_uid -> URL 작성할 때 user_uid 필요해서 사용힌다.
        serializer = CardSerializer(data={**request.data, 'user_uid': user_uid})

        if serializer.is_valid():
            data = serializer.validated_data
            with driver.session() as session:
                uid = str(uuid.uuid4())
                data['card_uid'] = uid

                # 카드 추가
                session.run("""
                    CREATE (card:CARD {
                        uid: $card_uid,
                        name: $card_name,
                        email: $card_email,
                        phone: $card_phone,
                        intro: $card_intro,
                        photo: $card_photo,
                        created_at: date($created_at)
                    })
                """, **data)

                # 동일한 uid를 가진 유저를 찾아 카드와 연결 (HAVE 관계로 연결)
                session.run("""
                    MATCH (user:USER {uid: $user_uid}), (card:CARD {uid: $card_uid})
                    MERGE (user)-[r:HAVE]->(card)
                """, user_uid=user_uid, card_uid=data['card_uid'])

            return Response({
                "message": "본인 명함 등록 성공",
                "result": data
            }, status=status.HTTP_201_CREATED)

        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#RememberPlus/backend/neo_db/urls.py
path('users/register/', RegisterView.as_view()),

연결해보기

  • USER 만들기

  • CARD 만들기(user_uid 같으면 HAVE관계 자동으로 생성)

- postman 쓸 때 맨 마지막은 , 안쓰기

- postman 쓸 때 “” 누워져 있지 말고 일짜로 큰 따음표가 되어야 함. 이것때문에 오류 날 수도 있음.

 

 

2. RELATION 관계

serlializers.py

# RememberPlus/backend/neo_db/serlializers.py
class RelationSerializer(serializers.Serializer):
    relation_uid = serializers.UUIDField(read_only=True)
    relation_name = serializers.CharField(required=True)
    memo = serializers.CharField()
    created_at = serializers.DateTimeField(read_only=True)
    updated_at = serializers.DateTimeField(read_only=True)

models.py

# RememberPlus/backend/neo_db/models.py
class RELATION(StructuredRel):
    relatoion_uid = StringProperty()  # UUID는 문자열로 저장됩니다.(이름 변경)
    relation_name = StringProperty(required=True)
    memo = StringProperty()
    created_at = DateTimeProperty(default_now=True)
    updated_at = DateTimeProperty(default_now=True)

views.py

# RememberPlus/backend/neo_db/views.py
class UserRelationView(APIView):
    def post(self, request, user_uid):
        data = request.data
        card_phone = data.get('card_phone')  # Change user_phone to card_phone
        relation_name = data.get('relation_name')
        memo = data.get('memo', '')

        with driver.session() as session:
            result = session.run("MATCH (u:USER {uid: $user_uid}) RETURN u.uid as user_uid", user_uid=user_uid)
            user1 = result.single()
            if user1 is None:
                logging.error("User with uid %s not found", user_uid)
                return Response({"message": "uid를 찾을 수 없습니다.", "result": None},
                                status=status.HTTP_400_BAD_REQUEST)

            result = session.run("MATCH (u:USER {phone: $card_phone}) RETURN u", card_phone=card_phone)  # Change user_phone to card_phone
            user2 = result.single()
            if user2 is None:
                logging.error("User with phone %s not found", card_phone)  # Change user_phone to card_phone
                return Response({"message": "전화번호를 찾을 수 없습니다.", "result": None},
                                status=status.HTTP_400_BAD_REQUEST)

            # Connect the users with the relation
            session.run("""
                MATCH (u1:U), (u2:User)
                WHERE u1.uid = $uid1 AND u2.phone = $phone2
                MERGE (u1)-[r:RELATION {relation_name: $name, memo: $memo}]->(u2)
            """, uid1=user1['user_uid'], phone2=card_phone, name=relation_name, memo=memo)  # Change user_phone to card_phone

        return Response({"message": "회원 끼리 연결 성공"},
                        status=status.HTTP_201_CREATED)

urls.py

path('relations/user/<str:user_uid>/', UserRelationView.as_view(), name='create-relation'),
# user_uid -> 관계를 연결하고 싶은 사람

연결해보기

  • 연결 당할 유저 하나 만들기

  • ssojungg → minmin 관계 만들기(minmin 인식 하는 법은 고유한 전화번호를 통해서 인식함)