sql >> Databáze >  >> RDS >> Database

Zábava s novými funkcemi Postgres od Djanga

Tento příspěvek na blogu popisuje, jak používat nová pole ModelField specifická pro PostgreSQL uvedená v Django 1.8 – ArrayField, HStoreField a Range Fields.

Tento příspěvek je věnován úžasným podporovatelům této kampaně na Kickstarteru, kterou dal dohromady Marc Tamlyn, skutečný playa, který to umožnil.


Klub Playaz?

Protože jsem velký geek a nemám šanci se někdy dostat do skutečného Playaz Clubu (a protože v den 4 byl Tay bomba), rozhodl jsem se vybudovat svůj vlastní virtuální online Playaz Club. co to přesně je? Soukromá sociální síť pouze pro pozvané cílená na malou skupinu stejně smýšlejících jedinců.

V tomto příspěvku se zaměříme na model uživatele a prozkoumáme, jak nové funkce PostgreSQL společnosti Django podporují modelování. Nové funkce, o kterých se zmiňujeme, jsou pouze PostgreSQL, takže se neobtěžujte zkoušet, pokud nemáte svou databázi ENGINE rovno django.db.backends.postgresql_psycopg2 . Budete potřebovat verzi>=2.5 psycopg2 . Aight playa, pojďme na to.

Ahoj, když budeš se mnou! :)



Modelování zástupce Playa

Každá hra má zástupce a chtějí, aby o jejich zástupci věděl celý svět. Vytvořme si tedy uživatelský profil (neboli „zástupce“), který umožní každému z našich playaz vyjádřit svou individualitu.

Zde je základní model pro zástupce 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 specifického pro 1.8 výše. Jen standardní model pro rozšíření základního uživatele Django, protože playa stále potřebuje uživatelské jméno a e-mailovou adresu, že? Navíc jsme přidali dvě nová pole pro uložení krytu Playaz a kódu oblasti.



Bankroll a RangeField

Na hraní nestačí jen klepat na kapotu. Playaz se často rád chlubí svým bankrollem, ale zároveň nechce dát lidem vědět, jak velký ten bankroll je. Můžeme to modelovat pomocí jednoho z nových Postgres Range Fields. Samozřejmě použijeme BigIntegerRangeField lépe modelovat masivní číslice, ne?

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

Pole rozsahů jsou založena na objektech psycopg2 Range a lze je použít pro Numeric a DateRanges. Po migraci bankrollového pole do databáze můžeme interagovat s našimi poli range tím, že jim předáme objekt range, takže vytvoření naší první hry by vypadalo asi takto:

>>>
>>> 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()

Všimněte si tohoto řádku:calvins_rep.bankroll = (100000000, 150000000) . Zde nastavujeme pole rozsahu pomocí jednoduché n-tice. Hodnotu je také možné nastavit pomocí NumericRange objekt takto:

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

To je v podstatě stejné jako použití n-tice. Je však důležité vědět o NumericRange objekt, který se používá k filtrování modelu. Pokud bychom například chtěli najít všechny hry, jejichž bankroll byl větší než 50 milionů (to znamená, že celý rozsah bankrollu je větší než 50 milionů):

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

A to vrátí seznam těch her. Případně, pokud bychom chtěli najít všechny hry, jejichž bankroll je „někde v rozmezí 10 až 15 milionů“, mohli bychom použít:

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

To by vrátilo všechny hry, které mají rozsah bankrollu, který zahrnuje alespoň část z rozsahu 10 až 15 milionů. Absolutnějším dotazem by byly všechny hry, které mají bankroll plně mezi rozsahem, tedy každý, kdo vydělává alespoň 10 milionů, ale ne více než 15 milionů. Tento dotaz by vypadal takto:

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

Více informací o dotazech založených na rozsahu naleznete zde.



Skillz jako ArrayField

Není to všechno o bankrollu, playaz dostal skillz, všechny druhy skillz. Pojďme je modelovat pomocí pole ArrayField.

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

Chcete-li deklarovat ArrayField musíme mu dát první argument, kterým je základní pole. Na rozdíl od seznamů Python musí ArrayFields deklarovat každý prvek seznamu jako stejný typ. Basefield deklaruje, o jaký typ se jedná, a může to být kterýkoli ze standardních typů polí modelu. Ve výše uvedeném případě jsme právě použili CharField jako náš základní typ, což znamená skillz bude pole řetězců.

Ukládání hodnot do ArrayField je přesně tak, jak očekáváte:

>>>
>>> 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()

Hledání her podle skillz

Pokud potřebujeme konkrétní playa s konkrétní dovedností, jak je najdeme? Použijte __contains filtr:

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

Pro hráče, kteří mají některou z dovedností [‚rappin‘, ‚djing‘, ‚producing‘], ale žádné jiné dovednosti, můžete zadat dotaz takto:

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

Nebo pokud chcete najít někoho, kdo má některou z určitých dovedností:

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

Mohli byste dokonce najít pouze ty lidi, kteří uvedli dovednost jako svou první dovednost (protože každý uvádí svou nejlepší dovednost jako první):

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



Hra jako HStore

Hru lze považovat za seznam různých náhodných dovedností, které může mít hra. Protože hra zahrnuje všemožné věci, modelujme ji jako pole HStore, což v podstatě znamená, že tam můžeme vložit jakýkoli starý slovník Pythonu:

game = pgfields.HStoreField()

Zamyslete se nad tím, co jsme tu právě udělali. HStore je docela velký. V podstatě umožňuje ukládání dat typu „NoSQL“ přímo uvnitř postgreSQL. Navíc, protože je to uvnitř PostgreSQL, můžeme propojit (prostřednictvím cizích klíčů) tabulky, které obsahují data NoSQL, s tabulkami, které ukládají běžná data typu SQL. Obojí můžete dokonce uložit do stejné tabulky v různých sloupcích, jak to děláme zde. Možná, že hry Playas už nemusí používat toho žongléra, všeříkajícího MongoDB…

Vraťme se k podrobnostem implementace, pokud se pokusíte migrovat nové pole HStore do databáze a skončíte s touto chybou-

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

-pak je vaše databáze PostgreSQL starší než 8.1 (čas na upgrade, přehrávání) nebo nemá nainstalované rozšíření HStore. Mějte na paměti, že v PostgreSQL se rozšíření HStore instaluje na databázi a ne na celý systém. Chcete-li jej nainstalovat z příkazového řádku psql, spusťte následující SQL:

CREATE EXTENSION hstore

Nebo pokud chcete, můžete to udělat pomocí SQL Migration s následujícím migračním souborem (za předpokladu, že jste byli připojeni k databázi jako superuživatel):

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = []

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

Nakonec se také budete muset ujistit, že jste přidali 'django.contrib.postgres' na 'settings.INSTALLED_APPS' používat pole HStore.

S tímto nastavením můžeme přidávat data do našeho HStoreField game tím, že na to hodíte slovník takto:

>>>
>>> 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()

Mějte na paměti, že diktát musí používat pouze řetězce pro všechny klíče a hodnoty.

A nyní několik dalších zajímavých příkladů…



Propz

Pojďme napsat funkci „ukázat hru“, která prohledá hru playaz a vrátí seznam playaz, které odpovídají. Zcela podivínsky hledáme v poli HStore jakékoli klíče předané do funkce. Vypadá to nějak takto:

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

Výše jsme použili has_key filtr pro pole HStore, aby vrátil sadu dotazů, pak ji dále filtroval pomocí funkce values ​​(hlavně proto, aby ukázal, že můžete řetězit django.contrib.postgres věci s běžnou sadou dotazů).

Návratovou hodnotou by byl seznam slovníků:

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

Jak se říká, Game rozpozná hru a nyní ji můžeme hledat i my.



High Rollers

Pokud věříme tomu, co nám playaz říká o jejich bankrollech, pak to můžeme použít k jejich seřazení do kategorií (protože jde o rozsah). Přidejme hodnocení Playa založené na bankrollu s následujícími úrovněmi:

  • young buck – bankroll méně než sto tisíc

  • balla – bankroll mezi 100 000 a 500 000 s dovedností „ballin“

  • playa – bankroll mezi 500 000 a 1 000 000 se dvěma dovednostmi a nějakou hrou

  • high roller – bankroll vyšší než 1 000 000

  • O.G. – má dovednost „gangsta“ a herní klíč „stará škola“

Dotaz na balla je níže. Toto by byl přísný výklad, který by vrátil pouze ty, jejichž celý rozsah bankrollu je ve stanovených limitech:

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

Zbytek si vyzkoušejte sami na procvičení. Pokud potřebujete pomoc, přečtěte si Dokumenty.



  1. Co to znamená, když je proces PostgreSQL v transakci nečinný?

  2. Získání názvu aktuální funkce uvnitř funkce pomocí plpgsql

  3. Vyhledejte v poli JSON objekt obsahující hodnotu odpovídající vzoru

  4. Jak zrušit omezení v SQL Server (T-SQL)