Jeszcze jeden blog o programowaniu

Radosne twórczości leniwego programisty

Archive for the ‘Frameworki’ Category

Sortowanie po wirtualnej kolumnie w Django

leave a comment »

Nie tak dawno temu w ramach jednego z zadań w Django było uporządkowanie wyników wg innego klucza niż najprostsze ORDER BY. Chodziło o nadanie pewnego rodzaju wag dla wierszy, które możliwie najlepiej wpasowały się w poniższe kryteria:

  • pierwszeństwo miały wiersze, które zawierały dokładne dopasowanie szukanej frazy
  • następnie wiersze, które od szukanej frazy się zaczynały
  • kolejno wiersze, które na podaną frazę się kończyły
  • kończąc wierszami, które podaną frazę zawierały w dowolnym miejscu
  • opcjonalnie pozostałe wiersze, jeśli query nie było jedynym kryterium filtrowania.

Przydatny okazał się poniższy kawałek kodu tworzący nieistniejącą w modelu CaseWhen columnę exact w postaci nowych warunków w obiekcie QuerySet  – po której następnie sortował:

Dodatkowe porządkowanie wg kolumny name służy do alfabetycznego uporządkowania wierszy, którym została nadana ta sama waga.

Jeśli nie zostanie przekazana fraza do szukania (parametr q) używana jest fraza beer. Żeby mieć pogląd jakie rzeczywiście wyniki są zwracane – w migracji aplikacji casewhen dodaję kilka wierszy do bazy.

Rozwiązanie zostało wdrożone w ramach integracji z Django REST Framework, ale chodzi tylko o zasadę działania, więc kod można wykorzystać także bez DRF.

Oczywiście całość do przejrzenia bezpośrednio na GitHub.

Written by Filip Górczyński

2018.03.07 at 17:14:26

Wykonanie kodu przy starcie aplikacji w Django

leave a comment »

Wielokrotnie zdarzyło mi się (i pewnie nie tylko mi) musieć uzupełnić jakimiś wartościami bazę danych w trakcie zmian w projekcie. Chodziło konkretnie o dane, które powinny się pojawić po wdrożeniu zmian i nie powinny dawać możliwości ich zmiany bądź usunięcia ze względu na potencjalny wpływ na działanie całej aplikacji.

Pierwszy pomysł tego rozwiązania to użycie migracji, jak w poniższym przykładzie:

Po wykonaniu migracji w bazie pojawią nam się wymagane wpisy. Jednak istotnym minusem tego rozwiązania jest to, że nadal można usunąć je bezpośrednio w bazie czy nawet w panelu administracyjnym Django i nie zostaną one odtworzone.

Kolejne podejście do problemu to przeniesienie kodu odpowiedzialnego za dodawanie wpisów do bazy do pliku apps.py, który uruchamiany jest przy starcie aplikacji – czyli praktycznie zawsze po restarcie serwera. Wrzucenie kodu do metody ready pozwoli nam obejść w całkiem elegancki sposób wspomniany wcześniej problem:

Na co zwrócić musimy uwagę, w pliku __init__.py naszej aplikacji musimy jawnie wskazać ścieżkę do pliku konfiguracyjnego aplikacji, jako że plik ten jest opcjonalny:

Warto także zerknąć na kilka innych kawałków kodu, m. in. uniemożliwienie edytowania kluczowych informacji w panelu administracyjnym Django czy usuwanie tych danych. Zauważyć też można 2 drobne usprawnienia: 1) wizualna reprezentacja zapisanego koloru w panelu administracyjnym dzięki użyciu funkcji format_html oraz 2) zmiana tytułu kolumny w panelu administracyjnym poprzez właściwość short_description.

Kawałek kodu związany z synchronizacją modeli z bazą danych został zaczerpnięty ze StackOverflow, a błąd dotyczący braku synchronizacji ujawnił się dopiero przy uruchomieniu testów.

Cały kod do pobrania i przejrzenia znaleźć można na GitHub.

Written by Filip Górczyński

2018.03.05 at 09:11:29

VueJS 2 – dostęp do konfiguracji środowiska

leave a comment »

vuejs logoW każdym co bardziej złożonym projekcie zachodzi potrzeba przechowywania różnych konfiguracji w zależności od środowiska: developerskiego, produkcyjnego, testowego, eksperymentalnego, niebieskiego i każdego innego. Oczywiście framework VueJS nie odstaje od normy i również oferuje możliwość takiej konfiguracji.

Na początku od razu zaznaczam, że zmiany w plikach konfiguracyjnych lub tworzenie nowych plików wymaga ponownego przebudowania i uruchomienia aplikacji – brak odzwierciedlania jakichkolwiek zmian w aplikacji może się okazać dość frustrujące jeśli zapomnimy o tej czynności – a często w konsoli widzimy, że się przebudowało – tylko jednak coś zmian z konfiguracji nie chwycił.

Konfiguracja dla różnych środowisk przechowywana jest domyślnie w 3 plikach (po utworzeniu czystego projektu):

Wyżej wymienione pliki ładowane są dokładnie w tej kolejności ewentualnie rozszerzając lub nadpisując dotychczasowe wartości zmiennych, więc w czystej instalacji na początku wczytywany jest plik prod.env.js, stałe w nim zawarte nadpisywane są plikiem dev.env.js a te z kolei test.env.js. Proste i logiczne (…długie jak drzewo genealogiczne naszej rasy…)

Oczywiście nic nie stoi na przeszkodzie aby, jeśli zajdzie taka potrzeba, dodawać swoje pliki konfiguracyjne definiujące ustawienia dla nowych środowisk. Np. staging – dodając przykładowo plik staging.env.js o przykładowej treści:

i wtedy np. w pliku dev.env.js rozszerzamy środowisko stagingEnv – a nie prodEnv jak to jest domyślnie.

Samo ustawienie bieżącego środowiska – wg którego budowany i uruchamiany jest VueJS odbywa się w pliku ./projekt/src/main.js w linijce:

chociaż lepszą z praktycznego punktu widzenia wersją byłaby poniższa:

I teraz, jeśli zawsze (we wszystkich środowiskach) potrzebujemy w aplikacji jakieś stałe to definiujemy je w pliku prod.env.js odpowiednio nadpisując w pozostałych plikach, jeśli oczywiście jakieś zmiany będą potrzebne.

W komponentach nic nie musimy importować, a dostęp do zmiennej jest wygląda w taki sposób: process.env.API_URL

Jeśli zbudujemy teraz projekt dla odpowiedniego środowiska, np.: dla produkcji npm run build otrzymamy katalog dist, w którym to znajduje się zbudowana chwilę temu aplikacja. Przechodząc w linii poleceń do tego katalogu cd ./projekt/dist i uruchamiając tymczasowy serwer python3 -m http.server 8181, w przeglądarce pod adresem 127.0.0.1:8181 powinna być dostępna nasza aplikacja – warto w tym miejscu potwierdzić różniące się między środowiskami zmienne, żeby nie było nieprzyjemnych niespodzianek.

Written by Filip Górczyński

2018.02.26 at 16:50:47

Django – zwracanie pustego zbioru

leave a comment »

QuerySet to jedna z podstawowych klas, z którą będziemy pracować w trakcie pisania aplikacji w Django. Trafiłem ostatnio na problem, w którym należało zwrócić inne wyniki w zależności od tego, czy w żądaniu do serwera przesłana została zmienna w postaci pustego łańcucha znaków czy nie została wysłana w ogóle. Drobna różnica mająca ogromne znaczenie. Aby dokładniej zobrazować zaistniały problem postaram się to opisać z przykładami:

Żądany adres http://127.0.0.1/ skutkuje zwróceniem wszystkich wyników – brak jakiegokolwiek filtrowania

Żądany adres http://127.0.0.1/?q= skutkuje brakiem wyników – filtrowanie jest, ale wyszukiwanie po pustym łańcuchu – który de facto pasuje do każdego dowolnego łańcucha znaków też zwróciłoby wszystkie wyniki – a tutaj potrzebowałem zwrócić pusty zbiór.

Żądany adres http://127.0.0.1/q=abc skutkuje zwróceniem wszystkich wyników, które w swojej treści zawierają łańcuch znaków „abc” – tutaj sprawa jest oczywista.

Ponieważ zwrócić musiałem obiekt QuerySet sprawa się komplikowała – a rozwiązaniem okazał się taki prosty kawałek kodu:

Written by Filip Górczyński

2018.02.22 at 09:49:05

Czysty projekt VueJS 2 i używanie średników a zgodność ze standardami ESLint

leave a comment »

vuejs logo

JavaScript jako bardzo elastyczny język programowania nie wymaga używania średników na końcu instrukcji. Nie wymaga – i nawet zgodnie z zaproponowanym standardem JavaScript, nie zaleca się ich stosowania.

Jednak moim skromnym zdaniem – jako kogoś, kto kiedyś popełnił trochę kodu w C i Perlu – z jakiegoś powodu średniki zostały do składni wprowadzone, a ich stosowanie powoduje (ponownie – to tylko moje osobiste odczucie), że kod staje się też czytelniejszy i ładniejszy.

Utwórzmy zatem czysty projekt z ustawieniami jak poniżej – istotna jest linijka "Pick an ESLint preset Standard", gdyż różne standardy mogą się czepiać nadmiarowych średników lub ich braku.

VueJS – podczas inicjowania czystego projektu pozwala wybrać standard ESLint, w ramach którego sprawdzana będzie zgodność kodu z tym standardem, m. in. po uruchomieniu serwera deweloperskiego. Przy wyborze standardowego sprawdzania składni, dodanie średników na końcach instrukcji będzie skutkowało następującym  błędem:

Szczegóły błędu dostępne są pod adresem wskazanym w ramach ostrzeżenia: Extra semicolon.

Rozwiązaniem jest dodanie 'semi': [2, 'always'] do pliku .eslintrc.js:

Ponowne uruchomienie aplikacji będzie wymagało poprawienia (dodania) średników we wszystkich wskazanych miejscach, jednak nadal twierdzę, że nadmiarowy średnik jest lepszy niż jego pominięcie – gdyż próby zastępowania elementów składni wartościami domyślnymi mogą skutkować kodem podobnym do tego z Perla:

Całość dostępna w repozytorium.

Dodatkowe źródła i (głównie) kontrargumenty:

  1. JavaScript Style: Semicolons, or No?
  2. StandardJS#Semicolons
  3. JavaScript Semicolon Insertion. Everything you need to know
  4. An Open Letter to JavaScript Leaders Regarding Semicolons
  5. Understanding Automatic Semicolon Insertion in JavaScript

Written by Filip Górczyński

2018.02.22 at 09:23:51

Bootswatch, czyli darmowe motywy dla znudzonych Bootstrapem

leave a comment »

Ciężko znaleźć w branży webowej programistę, który nie słyszał o Bootstrapie. Podejrzewam jednak, że mniej osób słyszało o kolekcji darmowych motywów – Bootswatch.
Na przykładzie prostej aplikacji w Angularze chciałbym przedstawić instalację jednego z tych darmowych motywów.

Początek nie odbiega od tego, co zwykle robimy. Generujemy czysty projekt Angular, np. narzędziem ng-cli, dodajemy wymagane zależności i instalujemy paczki potrzebne do uruchomienia projektu.

Po krótkiej chwili, gdy otrzymamy informację, że wszystkie zależności zostały zainstalowane poprawnie dodajemy styl wybranego przez nas motywu do globalnych stylów ładowanych w aplikacji – w pliku .angular-cli.json zmieniamy sekcję styles:

Gdyby nie było to widoczne na pierwszy rzut oka, użyłem motywu flatly.

Oczywiście, żeby nie było zbyt pięknie musiałem też „podkraść” fragment zawartości pliku custom.min.css – był w postaci skompresowanej, ale po rozplątaniu dostajemy mniej więcej coś takiego jak poniżej. W dużej mierze chodzi o odstępy pionowe pomiędzy komponentami.

„Zainspirowany” szablonem HTML z przykładu tego motywu wybrałem tylko kilka jego fragmentów żeby pokazać, że jednak coś tam działa:

I to by było wszystko co należy zrobić. Oczywiście można pokusić się o dodanie kilku plików JavaScript, które obsługują takie działania jak popovery czy okienka modalne, ale to może innym razem.

Całość dostępna w repozytorium GitHub.

Written by Filip Górczyński

2018.02.16 at 18:09:51

CORS Headers – komunikacja VueJS i Django

leave a comment »

vuejs logoCross-Origin Resource Sharing (CORS) to mechanizm wykorzystujący dodatkowe nagłówki HTTP pozwalające różnym agentom (np. przeglądarkom) na dostęp do zasobów znajdujących się na innej domenie, porcie czy protokole niż aktualna. 

Na potrzeby wpisu zakładam, że framework (Django) i biblioteki (Vue.js i axios) z których będziemy korzystać – mamy już zainstalowane w projekcie.

W projekcie Vue wprowadźmy następujące zmiany:

W pliku App.vue:

W pliku config/dev.env.js:

Pliki src/assets/logo.png i src/components/HelloWorld.vue możemy wyrzucić, jako w tej chwili nie używane.

W backendzie natomiast, w pliku views.py naszej aplikacji (movies):

i dodajemy routing dla naszej aplikacji w pliku urls.py (plik ten domyślnie nie istnieje i należy go utworzyć):

Następnie dokunujemy zmian w plikach urls.py – głównym pliku routingu całego projektu Django:

oraz settings.py:

Startujemy serwery poniższymi poleceniami w odpowiednich katalogach:

Uruchamiamy przeglądarkę i otwieramy 2 zakładki. W pierwszej zweryfikujemy tylko, czy serwer Django zwraca prawidłową odpowiedź – JSON (http://127.0.0.1:8000) i jeśli tak, to od razu można ją zamknąć. W drugiej zakładce otwieramy narzędzia programisty i przechodzimy pod adres aplikacji Vue (http://127.0.0.1:8080).
Dziwne – w zakładce Network zobaczyć możemy, że żądanie GET do serwera się udało i nawet możemy podejrzeć zwrócone wyniki:

Czyli wszystko jest prawidłowo? No nie do końca niestety. O ile domena (host) – w tej sytuacji 127.0.0.1 nie są problemem – to sprawa komplikuje się właśnie w przypadku niezgodności portów i przeglądarka może nam w konsoli sypnąć następującym błędem:

Problem nasz rozwiązać możemy paczką django-cors-headers, jej instalacja nie odbiega za bardzo od instalacji innych paczek Pythona:

pip install django-cors-headers==2.1.0

Zmieniamy trochę w pliku settings.py (ale naprawdę ciut-ciut):

… restartujemy serwer Django i już, wchodząc na adres naszej aplikacji powinniśmy cieszyć się pobranymi z serwera danymi.

Wymagane paczki do postawienia projektu Django znajdują się  w katalogu backend/requirements/base.txt, natomiast całość kodu źródłowego bezpośrednio w repozytorium VueJS-Django-CORS.

Dla zainteresowanych można jeszcze poszukać informacji na temat Same Origin Policy.

Dodatkowe źródła (często z fajnymi obrazkami):

  1. MDN CORS
  2. Understanding CORS
  3. Understanding CORS: Cross-Origin Resource Sharing
  4. Understanding and using CORS

 

Written by Filip Górczyński

2018.02.09 at 13:42:07

%d blogerów lubi to: