Database
 sql >> Baza danych >  >> RDS >> Database

Zabawa z nowymi funkcjami Postgres w Django

Ten wpis na blogu opisuje, jak używać nowych pól ModelField specyficznych dla PostgreSQL wprowadzonych w Django 1.8 — ArrayField, HStoreField i Range Fields.

Ten post jest poświęcony wspaniałym sponsorom tej kampanii na Kickstarterze, stworzonej przez Marca Tamlyna, prawdziwego playa, dzięki któremu tak się stało.


Klub Playaz?

Ponieważ jestem wielkim maniakiem i nie mam szansy dostać się do prawdziwego klubu Playaz (i ponieważ w dniu 4 Tay był bombą), postanowiłem zbudować własny wirtualny klub Playaz online. Co to dokładnie jest? Prywatna, dostępna tylko na zaproszenie sieć społecznościowa skierowana do małej grupy osób o podobnych poglądach.

W tym poście skupimy się na modelu użytkownika i zbadamy, w jaki sposób nowe funkcje PostgreSQL w Django wspierają modelowanie. Nowe funkcje, o których mówimy, dotyczą tylko PostgreSQL, więc nie próbuj tego, chyba że masz bazę danych ENGINE równe django.db.backends.postgresql_psycopg2 . Będziesz potrzebować wersji>=2.5 psycopg2 . Dobra gra, zróbmy to.

Holla, jeśli jesteś ze mną! :)



Modelowanie przedstawiciela Playa

Każdy playa dostał reputację i chcą, aby cały świat dowiedział się o ich reputacji. Stwórzmy więc profil użytkownika (czyli „przedstawiciela”), który pozwoli każdemu z naszych playaz wyrazić swoją indywidualność.

Oto podstawowy model przedstawiciela playaz:

from django.db import models
from django.contrib.auth.models import User

class Rep(models.Model):
    playa = models.OneToOneField(User)
    hood = models.CharField(max_length=100)
    area_code = models.IntegerField()

Nic konkretnego do 1.8 powyżej. Po prostu standardowy model do rozszerzenia bazowego użytkownika Django, bo playa nadal potrzebuje nazwy użytkownika i adresu e-mail, prawda? Dodatkowo dodaliśmy dwa nowe pola do przechowywania osłony Playaz i numeru kierunkowego.



Bankroll i RangeField

Na zabawę reperowanie kaptura nie zawsze wystarcza. Playaz często lubi afiszować się ze swoim bankrollem, ale jednocześnie nie chce, aby ludzie dokładnie wiedzieli, jak duży jest ten bankroll. Możemy to wymodelować za pomocą jednego z nowych pól strzeleckich Postgres. Oczywiście użyjemy BigIntegerRangeField lepiej modelować masywne cyfry, prawda?

bankroll = pgfields.BigIntegerRangeField(default=(10, 100))

Pola zakresów są oparte na obiektach zakresów psycopg2 i mogą być używane jako zakresy numeryczne i zakresy dat. Gdy pole bankroll zostanie przeniesione do bazy danych, możemy wchodzić w interakcje z naszymi polami zakresu, przekazując mu obiekt zakresu, więc tworzenie naszej pierwszej playy wyglądałoby mniej więcej tak:

>>>
>>> from playa.models import Rep
>>> from django.contrib.auth.models import User
>>> calvin = User.objects.create_user(username="snoop", password="dogg")
>>> calvins_rep = Rep(hood="Long Beach", area_code=213)
>>> calvins_rep.bankroll = (100000000, 150000000)
>>> calvins_rep.playa = calvin
>>> calvins_rep.save()

Zwróć uwagę na ten wiersz:calvins_rep.bankroll = (100000000, 150000000) . Tutaj ustawiamy pole zakresu za pomocą prostej krotki. Możliwe jest również ustawienie wartości za pomocą NumericRange taki obiekt:

from psycopg2.extras import NumericRange
br = NumericRange(lower=100000000, upper=150000000)
calvin.rep.bankroll = br
calvin.rep.save()

Jest to zasadniczo to samo, co użycie krotki. Jednak ważne jest, aby wiedzieć o NumericRange obiekt, który jest używany do filtrowania modelu. Na przykład, gdybyśmy chcieli znaleźć wszystkie playa, których bankroll był większy niż 50 milionów (co oznacza, że ​​cały zakres bankrolla jest większy niż 50 milionów):

Rep.objects.filter(bankroll__fully_gt=NumericRange(50000000, 50000000))

A to zwróci listę tych odtworzeń. Alternatywnie, gdybyśmy chcieli znaleźć wszystkie playa, których bankroll wynosi „gdzieś w przedziale od 10 do 15 milionów”, moglibyśmy użyć:

Rep.objects.filter(bankroll__overlap=NumericRange(10000000, 15000000))

Zwróciłoby to wszystkie playa, których bankroll obejmuje przynajmniej część z przedziału od 10 do 15 milionów. Bardziej bezwzględnym zapytaniem byłyby wszystkie playa, które mają bankroll w pełni mieszczący się w przedziale, tj. każdy, kto zarabia co najmniej 10 milionów, ale nie więcej niż 15 milionów. To zapytanie wyglądałoby tak:

Rep.objects.filter(bankroll__contained_by=NumericRange(10000000, 15000000))

Więcej informacji na temat zapytań na podstawie zakresu można znaleźć tutaj.



Skillz jako ArrayField

Nie chodzi tylko o bankroll, playaz ma skillz, wszelkiego rodzaju skillz. Zamodelujmy je za pomocą ArrayField.

skillz = pgfields.ArrayField(
    models.CharField(max_length=100, blank=True),
    blank = True,
    null = True,
)

Aby zadeklarować ArrayField musimy podać jej pierwszy argument, którym jest pole bazowe. W przeciwieństwie do list Pythona, ArrayFields musi deklarować każdy element listy jako ten sam typ. Basefield deklaruje, jaki to jest typ, i może to być dowolny ze standardowych typów pól modelu. W powyższym przypadku właśnie użyliśmy CharField jako nasz typ bazowy, co oznacza skillz będzie tablicą ciągów.

Przechowywanie wartości w ArrayField jest dokładnie taki, jak oczekujesz:

>>>
>>> from django.contrib.auth.models import User
>>> calvin = User.objects.get(username='snoop')
>>> calvin.rep.skillz = ['ballin', 'rappin', 'talk show host', 'merchandizn']
>>> calvin.rep.save()

Znajdowanie rozgrywek według umiejętności

Jeśli potrzebujemy konkretnego playa z konkretną umiejętnością, jak go znajdziemy? Użyj __contains filtr:

Rep.objects.filter(skillz__contains=['rappin'])

W przypadku graczy, którzy mają którąkolwiek z umiejętności [„rapowanie”, „djing”, „produkcja”], ale nie mają żadnych innych umiejętności, możesz zadać takie zapytanie:

Rep.objects.filter(skillz__contained_by=['rappin', 'djing', 'producing'])

Lub jeśli chcesz znaleźć kogoś, kto ma jakąkolwiek z określonej listy umiejętności:

Rep.objects.filter(skillz__overlap=['rappin', 'djing', 'producing'])

Możesz nawet znaleźć tylko te osoby, które wymieniły umiejętność jako swoją pierwszą umiejętność (ponieważ każdy podaje swoją najlepszą umiejętność jako pierwszą):

Rep.objects.filter(skillz__0='ballin')



Gra jako HSstore

Gra może być traktowana jako lista różnych, losowych umiejętności, które może posiadać playa. Ponieważ Gra obejmuje wszystkie rodzaje rzeczy, zamodelujmy ją jako pole HStore, co w zasadzie oznacza, że ​​możemy tam umieścić dowolny stary słownik Pythona:

game = pgfields.HStoreField()

Poświęć chwilę, aby pomyśleć o tym, co właśnie tutaj zrobiliśmy. HStore jest dość duży. Zasadniczo pozwala na przechowywanie danych typu „NoSQL”, bezpośrednio w postgreSQL. Dodatkowo, ponieważ znajduje się on w PostgreSQL, możemy łączyć (za pomocą kluczy obcych) tabele zawierające dane NoSQL z tabelami, które przechowują zwykłe dane typu SQL. Możesz nawet przechowywać oba w tej samej tabeli w różnych kolumnach, tak jak robimy tutaj. Może playas nie muszą już używać tego junkie, wszechogarniającego MongoDB…

Wracając do szczegółów implementacji, jeśli spróbujesz przenieść nowe pole HStore do bazy danych i skończysz z tym błędem-

django.db.utils.ProgrammingError: type "hstore" does not exist

-to twoja baza danych PostgreSQL jest starsza niż 8.1 (czas na aktualizację, playa) lub nie ma zainstalowanego rozszerzenia HStore. Należy pamiętać, że w PostgreSQL rozszerzenie HStore jest instalowane na bazę danych, a nie na cały system. Aby zainstalować go z wiersza poleceń psql, uruchom następujący kod SQL:

CREATE EXTENSION hstore

Lub jeśli chcesz, możesz to zrobić poprzez migrację SQL z następującym plikiem migracji (zakładając, że jesteś połączony z bazą danych jako superużytkownik):

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.RunSQL("CREATE EXTENSION IF NOT EXISTS hstore")
    ]

Na koniec musisz również upewnić się, że dodałeś 'django.contrib.postgres' do 'settings.INSTALLED_APPS' aby korzystać z pól HStore.

Dzięki tej konfiguracji możemy dodać dane do naszego HStoreField game rzucając w to słownikiem w ten sposób:

>>>
>>> calvin = User.objects.get(username="snoop")
>>> calvin.rep.game = {'best_album': 'Doggy Style', 'youtube-channel': \
    'https://www.youtube.com/user/westfesttv', 'twitter_follows' : '11000000'}
>>> calvin.rep.save()

Pamiętaj, że dyktat może używać tylko ciągów dla wszystkich kluczy i wartości.

A teraz kilka ciekawszych przykładów…



Propz

Napiszmy funkcję „pokaż grę”, która przeszuka grę playaz i zwróci listę pasujących playaz. W kategoriach geeków przeszukujemy pole HStore w poszukiwaniu kluczy przekazanych do funkcji. Wygląda mniej więcej tak:

def show_game(key):
    return Rep.Objects.filter(game__has_key=key).values('game','playa__username')

Powyżej użyliśmy has_key filtr dla pola HStore w celu zwrócenia zestawu zapytań, a następnie przefiltrowanie go za pomocą funkcji wartości (głównie po to, aby pokazać, że można połączyć django.contrib.postgres rzeczy ze zwykłymi zestawami zapytań).

Zwróconą wartością byłaby lista słowników:

[
  {'playa__username': 'snoop',
  'game': {'twitter_follows': '11000000',
           'youtube-channel': 'https://www.youtube.com/user/westfesttv',
           'best_album': 'Doggy Style'
        }
  }
]

Jak mówią, Game rozpoznaje grę, a teraz możemy również wyszukać grę.



Wysokie stawki

Jeśli wierzymy w to, co playaz mówi nam o swoich bankrollach, możemy to wykorzystać do uszeregowania ich w kategoriach (ponieważ jest to zakres). Dodajmy ranking Playa oparty na bankrollu z następującymi poziomami:

  • młody dolar – bankroll mniej niż sto tysięcy

  • balla – bankroll między 100 000 a 500 000 z umiejętnością „ballin”

  • playa – bankroll między 500 000 a 1 000 000 z dwoma umiejętnościami i odrobiną gry

  • high roller – bankroll większy niż 1 000 000

  • O.G. – posiada umiejętność „gangsta” i klucz do gry „old-school”

Zapytanie o ballę znajduje się poniżej. Byłaby to ścisła interpretacja, która zwracałaby tylko tych, których cały zakres bankrolla mieści się w określonych granicach:

Rep.objects.filter(bankroll__contained_by=[100000, 500000], skillz__contains=['ballin'])

Wypróbuj resztę samodzielnie, aby poćwiczyć. Jeśli potrzebujesz pomocy, przeczytaj dokumentację.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zarządzanie rolami i statusami w systemie

  2. Czy komentarze mogą utrudniać działanie procedury składowanej?

  3. Raportowanie użycia opcji/pakietów bazy danych

  4. Czas przycinania od datetime – kontynuacja

  5. Jak zmienić nazwę tabeli w SQL?