Hi Nick,

Your email reminded me of an RDF ORM (Object RDF Model?) library I wrote a
couple of months ago. The initial prototype used Pydantic, but I removed it
to align the Python API with Django's ORM.

It is not released yet, but please see the small example below and provide
any feedback.

from rdflib import Graph
from rdflib.namespace import DCTERMS, SKOS, OWL, DCAT, RDFS, RDF

from rdflib_orm.db import models


class Common(models.Model):
    provenance = models.CharField(predicate=DCTERMS.provenance,
lang='en', required=True)

    class Meta:
        mixin = True


class ConceptScheme(Common):
    class_type = models.IRIField(predicate=RDF.type, value=SKOS.ConceptScheme)
    title = models.CharField(predicate=DCTERMS.title, lang='en', required=True)
    description = models.CharField(predicate=SKOS.definition,
lang='en', required=True)
    created = models.DateTimeField(DCTERMS.created, auto_now_add=True)
    modified = models.DateTimeField(DCTERMS.modified, auto_now=True)
    creator = models.IRIField(predicate=DCTERMS.creator, required=True)
    publisher = models.IRIField(predicate=DCTERMS.publisher, required=True)
    version = models.CharField(predicate=OWL.versionInfo, required=True)
    custodian = models.CharField(predicate=DCAT.contactPoint)
    see_also = models.IRIField(predicate=RDFS.seeAlso, many=True)

    def __repr__(self):
        return f'<{self.__uri__}>'


class Concept(Common):
    class_type = models.IRIField(predicate=RDF.type, value=SKOS.Concept)
    pref_label = models.CharField(predicate=SKOS.prefLabel, lang='en',
required=True)
    alt_labels = models.CharField(predicate=SKOS.altLabel, lang='en', many=True)
    definition = models.CharField(predicate=SKOS.definition,
lang='en', required=True)
    children = models.IRIField(predicate=SKOS.narrower, many=True,
inverse=SKOS.broader)
    other_ids = models.CharField(predicate=SKOS.notation, many=True)
    home_vocab_uri = models.IRIField(predicate=RDFS.isDefinedBy)

    def __repr__(self):
        return f'<{self.__uri__}>'


if __name__ == '__main__':
    g = Graph()
    g.bind('dcterms', DCTERMS)
    g.bind('skos', SKOS)
    g.bind('dcat', DCAT)
    g.bind('owl', OWL)
    models.Database.set_db(g, base_uri='http://example.com/')

    concept_scheme = ConceptScheme(
        'https://linked.data.gov.au/def/concept_scheme',
        title='A concept scheme',
        description='A description of this concept scheme.',
        creator='https://linked.data.gov.au/org/cgi',  # Accepts a
URIRef or a string since the field is an IRIField.
        publisher='https://linked.data.gov.au/org/ga',
        version='0.1.0',
        provenance='Generated using Python',
        custodian='A custodian name',
        see_also=['http://example.com', 'http://another.example.com']
# Accepts a Python list since Field's many=True
    )

    concept_scheme.save()  # Save to store - currently memory store,
but works also for remote triplestore.

    concept_scheme.title = 'Modified concept scheme title'
    concept_scheme.save()  # Save changes - we changed the title field.

    concept_a = Concept(
        uri='https://linked.data.gov.au/def/concept_a',
        pref_label='A concept',
        alt_labels=['An alt label', 'another alt label'],
        definition='Definition of this concept.',
        # children=  # Optional field, no children on this concept.
        other_ids=['123', '456'],  # No language tag here :)
        home_vocab_uri=concept_scheme,  # Reference the Concept Scheme
Python object directly.
        provenance = 'Generated using RDFLib',
    )

    concept_a.save()

    concept_b = Concept(
        uri='https://linked.data.gov.au/def/concept_b',
        pref_label='Another concept',
        # alt_labels=  # Alt labels are optional.
        definition='Definition is not optional.',
        children=[concept_a],  # Reference the previous concept Python
object directly. Notice it will also add the inverse property :)
        # other_ids=  # Optional field again.
        home_vocab_uri=concept_scheme,
        provenance='Generated using rdflib-orm',
    )

    concept_b.save()

    # Let's do some queries.
    queryset = Concept.objects.all()
    print(queryset)
    # <QuerySet [<https://linked.data.gov.au/def/concept_b>,
<https://linked.data.gov.au/def/concept_a>]>

    # Get object by URI.
    concept_result =
Concept.objects.get('https://linked.data.gov.au/def/concept_a')
    print(concept_result)
    # <https://linked.data.gov.au/def/concept_a>
    print(concept_result.pref_label)
    # A concept
    print(concept_result.definition)
    # Definition of this concept.

    # Not implemented yet. Something planned for the future.
    # Get object by any property, e.g. notation.
    concept_result = Concept.objects.get(other_ids=123)

    print(len(g))  # 28 triples

    g.serialize('output.ttl', format='turtle')
    """ # Output of Graph.serialize()
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<https://linked.data.gov.au/def/concept_a> a skos:Concept ;
    dcterms:provenance "Generated using RDFLib"@en ;
    rdfs:isDefinedBy <https://linked.data.gov.au/def/concept_scheme> ;
    skos:altLabel "An alt label",
        "another alt label" ;
    skos:broader <https://linked.data.gov.au/def/concept_b> ;
    skos:definition "Definition of this concept."@en ;
    skos:notation "123",
        "456" ;
    skos:prefLabel "A concept"@en .

<https://linked.data.gov.au/def/concept_b> a skos:Concept ;
    dcterms:provenance "Generated using rdflib-orm"@en ;
    rdfs:isDefinedBy <https://linked.data.gov.au/def/concept_scheme> ;
    skos:definition "Definition is not optional."@en ;
    skos:narrower <https://linked.data.gov.au/def/concept_a> ;
    skos:prefLabel "Another concept"@en .

<https://linked.data.gov.au/def/concept_scheme> a skos:ConceptScheme ;
    dcterms:created "2021-05-26T22:13:50.720468"^^xsd:dateTime ;
    dcterms:creator <https://linked.data.gov.au/org/cgi> ;
    dcterms:modified "2021-05-26T22:13:50.723468"^^xsd:dateTime ;
    dcterms:provenance "Generated using Python"@en ;
    dcterms:publisher <https://linked.data.gov.au/org/ga> ;
    dcterms:title "Modified concept scheme title"@en ;
    rdfs:seeAlso <http://another.example.com>,
        <http://example.com> ;
    owl:versionInfo "0.1.0" ;
    skos:definition "A description of this concept scheme."@en ;
    dcat:contactPoint "A custodian name" .
    """


On Tue, May 25, 2021 at 11:56 PM Nicholas Car <
nicholas....@surroundaustralia.com> wrote:

> Dear RDFlib devs,
>
> I've just created a small tool to convert SKOS vocabularies presented in
> Excel to RDF: https://github.com/surroundaustralia/VocExcel
>
> This is hardly a new concept (PoolParty, SKOSPlay! and others have
> Excel-to-SKOS tools) but we need vocabs of a particular style.
>
> For this list's interest: I'm using RDFlib 6.0.0a0 along with pydantic
> Model classes which define Python classes mirroring major SKOS objects
> (ConceptScheme, Concept & Collection) and then convert those class
> instances to RDF, see
> https://github.com/surroundaustralia/VocExcel/blob/master/vocexcel/models.py
> .
>
> Does anyone else pydantic with rdflib and, if so, what equivalent to my 
> to_graph()
> methods do you use?
>
> Cheers,
>
> Nick
>
> --
>
>
> ______________________________________________________________________________________
> kind regards
> *Dr Nicholas Car*
> Data Systems Architect
> SURROUND Australia Pty Ltd and
> SURROUND NZ Limited
> Address  Level 9, Nishi Building,
>                   2 Phillip Law Street
>                   New Acton Canberra 2601
> Mobile     +61 477 560 177 <++61+477+560+177>
> Email       nicholas.car@surroundaustralia.comWebsite
> https://www.surroundaustralia.com
>
> *Enhancing Intelligence Within Organisations*
> *delivering evidence that connects decisions to outcomes*
>
>
> [image: Australian-National-University-Logo-1 – ANU Centre for Water and
> Landscape Dynamics]
>
> *Dr Nicholas Car*
> Adj. Senior Lecturer
>
> Research School of Computer Science
>
> The Australian National University
> Canberra ACT Australia
>
>
>
>  https://orcid.org/0000-0002-8742-7730
>
> https://cs.anu.edu.au/people/nicholas-car
>
> *Copyrights:*
> SURROUND Australia Pty Ltd is the copyright owner of all original content
> and attachments.
>
> All rights reserved.
>
> *Confidentiality Notice:*
> The contents of this email are confidential to the ordinary user of the
> email address to which
> it is addressed, and may also be privileged. If you are not the addressee
> of this email, you
> may not copy, forward, disclose, or otherwise use it or any part of it or
> its attachments in any
> form whatsoever. If you have received this email in error, please email
> the sender by replying
> to this message.
>
> --
> http://github.com/RDFLib
> ---
> You received this message because you are subscribed to the Google Groups
> "rdflib-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to rdflib-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/rdflib-dev/CAP7nqh1donE5o_Fedup4EbKtfUBJSmGmahUi5O8vq_md9jftJA%40mail.gmail.com
> <https://groups.google.com/d/msgid/rdflib-dev/CAP7nqh1donE5o_Fedup4EbKtfUBJSmGmahUi5O8vq_md9jftJA%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
http://github.com/RDFLib
--- 
You received this message because you are subscribed to the Google Groups 
"rdflib-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to rdflib-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rdflib-dev/CAOuzkyQcMcRAWNqVxB2UX5GUUChkwbu-RjQxgV%2BOT-KW%2BB4%3DYQ%40mail.gmail.com.

Reply via email to