1. 준비물

GeoDjango는 django project의 일종으로 위치 데이터를 다룰 수 있게 해줍니다. 위치 데이터는 보통 구글맵을 이용한 좌표 데이터를 의미한다고 봐도 됩니다. 그 외에도 3d나 2d 좌표를 이용한 계산 등의 기능도 가능케 합니다.

GeoDjango : https://docs.djangoproject.com/en/2.0/ref/contrib/gis/


models.py 에서 설정하는 여러가지 방법이 있지만 PointField를 쓰기로 했습니다. 


class Post(models.Model):
    
    author = models.ForeignKey(User, related_name='related_postwriter')
    text = models.TextField(null = True, blank = True)
    image = models.ImageField(null = True, blank = True, upload_to='gogo')
    created_date = models.DateTimeField(
        default=timezone.now
        )
    point = models.PointField(blank=False, null=False)
    #여기서 PointField를 쓴다. PointField는 좌표를 저장하기에 좋습니다.
 
    def __str__(self):              # __unicode__ on Python 2
        return self.author
cs


이젠 PointField의 정보를 views.py에서 다룰 차례입니다.

그 전에 admin.py에 Post 모델을 등록합니다.


from .models import Post
 
admin.site.register(Post)
cs


2. views.py 설정


그리고 views.py 에서 import는 이렇게 해 줍니다.


from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis.measure import D
cs


ViewSet class를 만듭니다.


class PostViewSet(viewsets.ModelViewSet):
    serializer_class = PostSerializer
    permission_classes = [IsAuthenticated]
    queryset = Post.objects.all()
cs


django-rest-framework 를 쓰고 있으니 import할 것이 있습니다. django-rest-framework를 더욱 편리하게 해줍니다.

django-rest-framework는 django 에서 RESTful API를 구성하기 쉽게 해 줍니다. 많이 사용되는 패키지입니다.

django-rest-framework : http://www.django-rest-framework.org/


from rest_framework import filters, viewsets, generics
 
cs


이러면 viewsets.ModelViewSet을 쓸 수 있습니다.


from blog.models import Post
 
cs

모델을 호출하지 않으면 동작하지 않습니다.


    def get_queryset(self) :
        lat = self.request.GET.get('user_lat''15')
        lon = self.request.GET.get('user_lon''13')
        userpoint = GEOSGeometry('POINT(' + lon + ' ' + lat + ')', srid=4326)
        self.result = []
        return self.result
cs


쿼리셋을 불러오는 일부분입니다. 여기에 옵션을 조금 더 추가합니다.


        while i<20:
            elasped_minutes = datetime.now() - timedelta(minutes=10*i)
            list_i = Post.objects.filter(point__distance_lte = (userpoint, D(m=i*500))).order_by("-created_date")
            if len(self.result) > 50:
                self.result = self.result[:50]
                break
            i += 1
cs



이렇게 되면 일정 거리에 있는 결과들을 결과값으로 가져오게 됩니다. 500m 단위로 필터를 반복하게 구성했습니다.


3. 작성자와 request.user 일치시키기

작성자는 글쓴 사람으로 등록되게 하겠습니다.

serializer의 self값에서 request요소를 받아내고 있음을 이용합니다.


    def perform_create(self, serializer):
        serializer.save(author=self.request.user)
cs


django-pipeline은 배포에 있어 static 파일들의 업데이트를 손쉽게 해주는 장점이 좋은 파이썬 패키지입니다.


1. 설치

pip install django-pipeline
cs


pip를 이용해서 설치합니다.


INSTALLED_APPS = (
    'pipeline',
)
cs


settings.py 에 앱을 추가합니다.


STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
cs
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'pipeline.finders.PipelineFinder',
)
cs


따로 static 파일들의 저장경로와 static 파일을 찾는 finder를 설정해줍니다. 기본 설정이 끝납니다.


2. 세부 설정


그다음 staticfiles_dir 을 참조하여 다른 설정들도 해야 합니다.

staticfiles_dir 과 비슷한 구조입니다.


PIPELINE = {
    'new_css': {
        'css': {
            'source_filenames': (
              'css/css_1.css',
              'css/css_help/*.css',
              'css/css_2.css'
            ),
            'output_filename''css/new_css_output.css'
        },
    },
    'new_js': {
        'js': {
            'source_filenames': (
              'js/jquery.js',
              'js/js_help/*.js',
              'js/js_1.js',
            ),
            'output_filename''js/new_js_output.js',
        }
    }
}
cs


이 것을 settings.py에 추가합니다. django-pipeline은 이 정보를 바탕으로 작업을 수행합니다. 일반 collectstatic 과정과 비슷하지만 다른 점은 pipeline을 통해 만들어진 static파일들은 각기 특이한 이름을 갖게 된다는 것입니다. 그러므로 브라우저가 파일을 로드할 시에 이름이 중복되기 때문에 추가로 로드하지 않는 경우를 막을 수 있습니다.


3. 사용법

그 후 template파일을 정리하면 됩니다. template파일에서도 불러오는 방법이 존재합니다.


{% load pipeline %}
{% new_css 'css' %}
{% new_js 'js' %}
cs

이렇게 불러오게 됩니다.

pipeline을 이용해서 collectstatic이 진행된 결과를 불러오게 됩니다.


여기서 settings.py에서 PIPELINE={} 안의 이름들을 지정할 때 혼동되기 쉽습니다.

그러므로 나중에 설정할 때는 편리하게 알아보기 쉬운 이름으로 설정하는 것이 좋을 것 같습니다.


1. 준비물

Dialog를 사용할 것입니다. Dialog를 위해 이런 코드를 써야 합니다.


import android.content.DialogInterface;
import android.content.Intent;
 
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatDialogFragment;    
 
    private void openDialog() {
    }
cs


이렇게 하면 Dialog가 열립니다.

Dialog 안에도 inflater를 써서 콘텐츠를 가져옵니다.


        LayoutInflater inflater = LayoutInflater.from(getContext());
        View subView = inflater.inflate(R.layout.dialog_layout, null);
cs


View도 가져옵니다. View를 가져올 시엔 inflater를 사용합니다. getContext()는 액티비티의 속성을 가져오기 위해 사용합니다.


        final EditText subEditText = (EditText) subView.findViewById(R.id.dialogEditText);
 
cs


EditText는 유저가 할 말을 전달하는 역할을 수행합니다.


그 외 기타 코드들 입니다.


        subEditText.setSelection(subEditText.length());
        AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getContext(), R.style.myDialog));
        builder.setTitle("Text to Post");
        builder.setView(subView);
        AlertDialog alertDialog = builder.create();
cs


Dialog는 builder로 create()해줘야 합니다.


2. 긍정, 부정 버튼

긍정 버튼은 이렇게 구현합니다.


        builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                mEditTextdialogOpenField.setText(subEditText.getText().toString());
            }
        });
cs


이러면 긍정적으로 버튼이 작동합니다. 질문에 긍정적으로 답했을 때 코드들이 실행되는 구조입니다.

반대로 부정 버튼은 이렇게 합니다.


        builder.setNegativeButton("Cancel"new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Snackbar.make(getView(), "Cancel", Snackbar.LENGTH_LONG).show();
            }
        });
cs


이러면 버튼이 부정적으로 동작하게 됩니다.


        builder.show();
 
cs


애써 만든 코드에 show()를 더해줘야 정상적으로 동작합니다.

+ Recent posts