개인학습용으로 정리한 내용임. 해당 블로그의 글 대부분 참고하여 진행함.
dJango로 restful API 서버만들기 [1] - django 서버 생성
소스코드 GIT : https://github.com/tkdlek11112/django_restful 강의영상 YouTube restfulAPI 서버란? API 서버인데 일종의 규칙을 적용하여 사용하기 편리하게 만든것! (자세한것은 구글링이나 영상 참조 >
cholol.tistory.com
1. 가상환경 만들기
$ python -m venv venv
2. 가상환경 활성화
$ source venv/Scripts/activate
3. django 설치
$ python -m pip install django=="2.2.6"
해당 블로그 글에서의 django version에 맞춰 설치함.
4. DRF 설치하기
$ python -m pip install djangorestframework
5. project 생성하기
$ django-admin startproject mobile_login_using_drf .
6. app 생성하기
$ django-admin startapp addresses
7. INSTALLED_APPS에 app 및 rest_framework 추가 + rest framework 관련 설정 추가(mobile_login_using_drf/settings.py)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'addresses', # 코드 추가
'rest_framework', # 코드 추가
]
# 코드 추가
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
8. model 설정(addresses/models.py)
from django.db import models
# 코드 추가
class Addresses(models.Model):
name = models.CharField(max_length=10)
phone_number = models.CharField(max_length=13)
address = models.TextField()
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created']
9. serializer 만들기(addresses/serializers.py)
# 코드 추가
from rest_framework import serializers
from .models import Addresses
class AddressesSerializer(serializers.ModelSerializer):
class Meta:
model = Addresses
fields = ['name', 'phone_number', 'address']
10. view 작성(addresses/views.py)
from django.shortcuts import render
# 코드 추가
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import Addresses
from .serializers import AddressesSerializer
from rest_framework.parsers import JSONParser
@csrf_exempt
def address_list(request):
if request.method == 'GET':
query_set = Addresses.objects.all()
serializer = AddressesSerializer(query_set, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = AddressesSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
@csrf_exempt
def address(request, pk):
obj = Addresses.objects.get(pk=pk)
if request.method == 'GET':
serializer = AddressesSerializer(obj)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = AddressesSerializer(obj, data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
obj.delete()
return HttpResponse(status=204)
@csrf_exempt
def login(request):
if request.method == 'POST':
data = JSONParser().parse(request)
search_name = data['name']
obj = Addresses.objects.get(name=search_name)
if data['phone_number'] == obj.phone_number:
return HttpResponse(status=200)
else:
return HttpResponse(status=400)
11. url 세팅(mobile_login_using_drf/urls.py)
from addresses import views
from django.urls import re_path, include
from django.contrib import admin
urlpatterns = [
re_path('admin/', admin.site.urls),
re_path('', include('addresses.urls')), # 그냥 localhost:8000으로 호출하면 아무것도 없으니까 계속 importerror 등등 발생해서 추가해줌
re_path('addresses/', views.address_list),
re_path('addresses/<int:pk>/', views.address),
re_path('login/', views.login),
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
계속해서 ImportError: cannot import name 'url' from 'django.conf.urls' 오류가 발생해서 내 상황에 맞게 코드 수정함[1].
12. migrate해주기
$ python manage.py makemigrations todo_app
$ python manage.py migrate
13. superuser 등록
$ ./manage.py createsuperuser
14. admin에 model 등록(addresses/admin.py)
admin 계정을 통해 model에 맞게 데이터 추가해보기. 등록된 데이터가 있어야 안드로이드 연동 후 실제로 연동되었는지 확인하는데 용이하니까.
from django.contrib import admin
from todo_app.models import Addresses # 코드 추가
admin.site.register(Addresses) # 코드 추가
14. 안드로이드 로그인 화면 간단하게 만들기(activity_main.xml)

15. 해당 로그인 화면에 맞게 작성할 틀 입력(MainActivity.kt)
package com.example.mobile_login_android_test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog // 코드 추가
import kotlinx.android.synthetic.main.activity_main.* // 코드 추가
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 코드 추가
button.setOnClickListener {
var textId = editTextTextPersonName.text.toString()
var textPw = editTextTextPassword.text.toString()
var dialog = AlertDialog.Builder(this)
dialog.setTitle("알람!")
dialog.setMessage("id = " + textId + "pw = " + textPw)
dialog.show()
}
}
}
16. gradle에 retrofit 설정 추가(build.gradle (:app))
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
// 코드 추가
// Retrofit
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
}
17. 인터넷 퍼미션 설정 추가(AndroidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobile_login_android_test">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Mobile_login_android_test">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" /> <!-- 코드 추가 -->
</manifest>
18. output용 파일 만들기(Login.kt)
output 정의용.
package com.example.mobile_login_android_test
// 코드 추가
data class Login(
var code : String,
var msg : String
)
19. input용 파일 만들기(LoginService.kt)
input 정의용.
package com.example.mobile_login_android_test
// 코드 추가
import retrofit2.Call
interface LoginService {
@FormUrlEncoded
@POST("/app_login/")
fun requestLogin(
@Field("userid") userid:String,
@Field("userpw") userpw:String
) : Call<Login>
}
20. retrofit 객체 생성(MainActivity.kt)
해당 객체 생성해야 django 서버랑 통신이 가능하니까.
package com.example.mobile_login_android_test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Retrofit // 코드 추가
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 코드 추가
var retrofit = Retrofit.Builder()
.baseUrl('http://172.30.1.27:8000') // 웹서버 실행되는 링크
.addConverterFactory(GsonConverterFactory.create())
.build()
button.setOnClickListener {
var textId = editTextTextPersonName.text.toString()
var textPw = editTextTextPassword.text.toString()
var dialog = AlertDialog.Builder(this)
dialog.setTitle("알람!")
dialog.setMessage("id = " + textId + "pw = " + textPw)
dialog.show()
}
}
}
baseUrl의 경우 cmd창에서 ipconfig 쳐서 IPv4인 부분에 대한 링크 입력하면 됨.
21. interface 객체 생성(MainActivity.kt)
var retrofit = Retrofit.Builder()
.baseUrl('http://172.30.1.27:8000') // 웹서버 실행되는 링크
.addConverterFactory(GsonConverterFactory.create())
.build()
// 코드 추가
var loginService = retrofit.create(LoginService::class.java)
22. 통신 상황에 따른 반응 설정(MainActivity.kt)
package com.example.mobile_login_android_test
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var retrofit = Retrofit.Builder()
.baseUrl('http://172.30.1.27:8000') // 웹서버 실행되는 링크
.addConverterFactory(GsonConverterFactory.create())
.build()
var loginService = retrofit.create(LoginService::class.java)
button.setOnClickListener {
var textId = editTextTextPersonName.text.toString()
var textPw = editTextTextPassword.text.toString()
loginService.requestLogin(textId, textPw).enqueue(object:Callback<Login>{
// 통신 실패 시
override fun onFailure(call: Call<Login>, t: Throwable) {
var dialog = AlertDialog.Builder(this@MainActivity)
dialog.setTitle("실패!")
dialog.setMessage("통신에 실패했습니다.")
dialog.show()
}
// 통신 성공 시
override fun onResponse(call: Call<Login>, response: Response<Login>) {
var login = response.body() // code, msg
var dialog = AlertDialog.Builder(this@MainActivity)
dialog.setTitle("알람!")
dialog.setMessage("code = " + login?.code + "msg = " + login?.msg)
dialog.show()
}
})
}
}
}
안드로이드 스튜디오 상에서 자동으로 override function 작성이 계속 안 되길래 그냥 다 직접 작성함.
▶▶▶ 여기서부터는 실습 영상과는 달리 내 코드에서 계속 오류 뜨는 것들 해결하는 과정.
23. active_main.xml에 있는 BUTTON 등의 ID값 Main activity로 가져오기 위한 설정하기(build.gradle(:app)) [2]
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions' # 코드 추가
}
해당 설정 후 Gradle과의 sync 맞춰주니 해당 각 컴포넌트?들의 이름에 뜨던 빨간 줄 사라짐.

24. '함수이름' overrides nothing 오류 해결하기(MainActivity.kt)

Callback과 Call이 import되지 않았어서 생긴 문제였음.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call # 코드 추가
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.Retrofit.Builder
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.Callback # 코드 추가
25. None of the following functions can be called with the arguments supplied. 오류 해결하기

해당 오류의 의미는 내가 입력한 해당 인수로 baseUrl이라는 함수를 호출하는게 불가능하다는 뜻.
baseUrl의 인수에 대해 '가 아니라 "로 수정해주니 해결됨[4].
java나 kotlin 등에서는 하나의 문자일 때만 '(따옴표), 2개 이상의 단어일 때는 "(쌍따옴표)를 사용하는 듯. 주의할 것.
26. 25 error 해결하면서 발생한 오류 해결하기

Not enough information to infer type variable T.
인자가 제대로 작성되지 않아서 발생하는 문제인 듯[5]. 인자에 대해서 디테일하게 작성해주면 사라지는 오류라고 함. kotlin을 사용하다보면 초기에 거의 무조건 발생하는? 오류라고 함.
var loginService: LoginService =
retrofit.create(LoginService::class.java)
이렇게 디테일하게 작성해주니 create에서는 빨간줄 사라짐.
27. Unresolved reference: java 오류 해결하기

내 kotlin 버전은 1.5.20임. [3]을 참고하여 androidx.core:core-ktx:1.9.0를 다운그레이드하여 1.5.2 또는 1.3.2로 한 후 sync까지 돌렸으나 효과 없음.

해당 부분 참고하여 1.5.1로도 수정하고 다시 sync 맞춰봤는데도 효과 없었음.
일단 다 적용해도 안 되니 github에 private으로 코드 올려뒀다가 안드로이드 다시 설치하고 코드 돌려보도록 해 볼 것.
효과 없음..
▶▶▶ Django 서버에 기능 및 url 추가하기
28. app_login 작성(views.py)
@csrf_exempt
def app_login(request):
if request.method == 'POST':
print("리퀘스트 로그" + str(request.body))
id = request.POST.get('userid', '')
pw = request.POST.get('userpw', '')
print("id = " + id + " pw = " + pw)
result = authenticate(username=id, password=pw)
if result:
print("로그인 성공!")
return JsonResponse({'code': '0000', 'msg': '로그인성공입니다.'}, status=200)
else:
print("실패")
return JsonResponse({'code': '1001', 'msg': '로그인실패입니다.'}, status=200)
android의 LoginService라는 interface를 API 삼아 통신?하기 위해 작성.
29. app_login 관련 url 추가(urls.py)
urlpatterns = [
re_path('admin/', admin.site.urls),
re_path('', include('addresses.urls')),
re_path('addresses/', views.address_list),
re_path('addresses/<int:pk>/', views.address),
re_path('login/', views.login),
re_path('app_login/', views.app_login), # 코드 추가
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
일단 웹서버나 제대로 완성하자. 제대로 구동되는지 보고 싶으면 자체적으로 unittest하는 걸로.
<reference>
[1] 참고 글1
[Error] importError: django.conf.url 에서 'url' 호출 실패
Django로 개인 프로젝트를 진행하려던 찰나에 , 기초 셋팅 과정에서 아래와 같은 오류를 만났습니다..ImportError: cannot import name 'url' from 'django.conf.urls' 해당 오류는 Django Version 4에서 더 이상
velog.io
[2] 참고 글2
Android Kotlin - Unresolved reference Error
active_main.xml 에 정의되어있는 TextView나 Button 의 ID값을, MainActivity 에서 바로 불러오려는데, * Ex) id 값이 @+id/box_one_text 면, 그냥 box_one_text 를 쓰려는 것임. 안되는거다. 위와같은 에러가 뜨는데, 해
ding-dong-in-future.tistory.com
[3] 참고 글3
Unresolved reference: java 오류
최근 개인 프로젝트를 위해 프로젝트를 새로 생성하고Activity를 이동하는 코드를 짜던 중 오류가 발생했다.위 코드에서 .java 부분에서 에러가 발생했는데..Unresolved reference: java으응?라이브러리를
velog.io
[4] 참고 글4
Too many characters in character literal 에러
기존에 있던것을 재개발해야해서 아무래도 파이썬보다는 자바쪽으로 하고싶어서 만지는도중 이런 에러를 발견함 4번째 라인에 빨간색으로 "Too many characters in character literal" 이라고 적혀있는데..
vesselsdiary.tistory.com
[5] 참고 글5
[Kotlin] Not enough information to infer type variable T 에러
Kotlin으로 안드로이드 프로그래밍은 처음 시작한다면 이 에러를 거의 100% 확률로 접할 수 있다. 물론 초기만 당하고, 한 번 당해보면 그 뒤부터는 당할 일이 없는 에러이기도 하다. 위의 에러를
like-tomato.tistory.com
'web' 카테고리의 다른 글
| [django] base와 virtual environment의 pip install 시 패키지 중복 문제 해결!! (1) | 2023.04.09 |
|---|---|
| [django] DRF(Django Rest Framework)와 안드로이드 연동 실습 (0) | 2023.03.13 |
| [django] Django rest framework(DRF)를 이용한 Mobile app을 위한 백엔드 구축 실습 (0) | 2023.03.10 |
| [django] URL dispatcher, URL conf 전체적으로 파악하고 정리하기 (0) | 2023.02.07 |
| [django] function-based view -> class-based view로 코드 수정해보기 (0) | 2023.02.06 |
댓글