README.md 7.97 KB
Newer Older
Sylvain Le Bon's avatar
Sylvain Le Bon committed
1 2 3 4 5 6
## Synopsis

This module is an add-on for Django REST Framework that serves a django model respecting the Linked Data Platform convention.

It aims at enabling people with little development skills to serve their own data, to be used with a LDP application.

Calum Mackervoy's avatar
Calum Mackervoy committed
7 8
Building a Startin' Blox application? Read this: https://git.happy-dev.fr/startinblox/devops/doc

Sylvain Le Bon's avatar
Sylvain Le Bon committed
9 10 11 12 13
## Requirements

* Django (known to work with django 1.11)
* Django Rest Framework
* pyld
14 15
* django-guardian
* djangorestframework-guardian
Sylvain Le Bon's avatar
Sylvain Le Bon committed
16 17 18

## Installation

Benoit Alessandroni's avatar
Benoit Alessandroni committed
19
1. Install this module and all its dependencies
Sylvain Le Bon's avatar
Sylvain Le Bon committed
20

21 22
```bash
$ pip install djangoldp
Sylvain Le Bon's avatar
Sylvain Le Bon committed
23 24
```

Benoit Alessandroni's avatar
Benoit Alessandroni committed
25
2. Create a django project
Sylvain Le Bon's avatar
Sylvain Le Bon committed
26
 
27 28
```bash
$ django-admin startproject myldpserver
Sylvain Le Bon's avatar
Sylvain Le Bon committed
29 30
```

Calum Mackervoy's avatar
Calum Mackervoy committed
31 32 33 34 35 36 37 38 39 40 41 42
3. Add DjangoLDP to INSTALLED_APPS
```python
INSTALLED_APPS = [
    ...
    # make sure all of your own apps are installed BEFORE DjangoLDP
    'djangoldp.apps.DjangoldpConfig',
]
```

IMPORTANT: DjangoLDP will register any models which haven't been registered, with the admin. As such it is important to add your own apps above DjangoLDP, so that you can use custom Admin classes if you wish

4. Create your django model inside a file myldpserver/myldpserver/models.py
43 44
Note that container_path will be use to resolve instance iri and container iri
In the future it could also be used to auto configure django router (e.g. urls.py)
Sylvain Le Bon's avatar
Sylvain Le Bon committed
45

46
```python
47
from djangoldp.models import Model
Sylvain Le Bon's avatar
Sylvain Le Bon committed
48

49
class Todo(Model):
Sylvain Le Bon's avatar
Sylvain Le Bon committed
50 51 52 53
    name = models.CharField(max_length=255)
    deadline = models.DateTimeField()
```

Calum Mackervoy's avatar
Calum Mackervoy committed
54
4.1. Configure container path (optional)
55 56
By default it will be "todos/" with an S for model called Todo

57
```python
58 59 60
<Model>._meta.container_path = "/my-path/"
```

Calum Mackervoy's avatar
Calum Mackervoy committed
61
4.2. Configure field visibility (optional) 
62 63
Note that at this stage you can limit access to certain fields of models using

64
```python
65 66 67 68 69 70 71
<Model>._meta.serializer_fields (<>list of field names to show>)
```

 For example, if you have a model with a related field with type **django.contrib.auth.models.User** you don't want to show personal details or password hashes.

E.g.

72
```python
73 74 75 76 77
from django.contrib.auth.models import User

User._meta.serializer_fields  = ('username','first_name','last_name')
```

78 79
Note that this will be overridden if you explicitly set the fields= parameter as an argument to LDPViewSet.urls(), and filtered if you set the excludes= parameter.

Calum Mackervoy's avatar
Calum Mackervoy committed
80
5. Add a url in your urls.py:
Alexandre's avatar
Alexandre committed
81

82
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
83 84
from django.conf.urls import url
from django.contrib import admin
Sylvain Le Bon's avatar
Sylvain Le Bon committed
85
from djangoldp.views import LDPViewSet
Sylvain Le Bon's avatar
Sylvain Le Bon committed
86
from .models import Todo
Sylvain Le Bon's avatar
Sylvain Le Bon committed
87 88

urlpatterns = [
89 90
    url(r'^', include('djangoldp.urls')),
    url(r'^admin/', admin.site.urls), # Optional
Sylvain Le Bon's avatar
Sylvain Le Bon committed
91 92
]
```
Alexandre's avatar
Alexandre committed
93

94 95 96 97
This creates 2 routes for each Model, one for the list, and one with an ID listing the detail of an object.

You could also only use this line in settings.py instead:

98
```python
99 100
ROOT_URLCONF = 'djangoldp.urls'
```
Sylvain Le Bon's avatar
Sylvain Le Bon committed
101

Calum Mackervoy's avatar
Calum Mackervoy committed
102
6. In the settings.py file, add your application name at the beginning of the application list, and add the following lines
Sylvain Le Bon's avatar
Sylvain Le Bon committed
103

104
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
105 106
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static')
LDP_RDF_CONTEXT = 'https://cdn.happy-dev.fr/owl/hdcontext.jsonld'
Calum Mackervoy's avatar
Calum Mackervoy committed
107 108 109
DJANGOLDP_PACKAGES = []
SITE_URL = 'http://localhost:8000'
BASE_URL = SITE_URL
Sylvain Le Bon's avatar
Sylvain Le Bon committed
110 111
```

Calum Mackervoy's avatar
Calum Mackervoy committed
112 113 114 115 116 117 118
* `LDP_RDF_CONTEXT` tells DjangoLDP where our RDF [ontology](https://www.w3.org/standards/semanticweb/ontology) is defined, which will be returned as part of our views in the 'context' field. This is a web URL and you can visit the value to view the full ontology online
* `DJANGOLDP_PACKAGES` defines which other [DjangoLDP packages](https://git.happy-dev.fr/startinblox/djangoldp-packages) we're using in this installation
* `SITE_URL` is the URL serving the site, e.g. `https://example.com/`
* `BASE_URL` may be different from SITE_URL, e.g. `https://example.com/app/`


7. You can also register your model for the django administration site
Sylvain Le Bon's avatar
Sylvain Le Bon committed
119

120
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
121 122 123 124 125 126
from django.contrib import admin
from .models import Todo

admin.site.register(Todo)
```

Calum Mackervoy's avatar
Calum Mackervoy committed
127
8. You then need to have your WSGI server pointing on myldpserver/myldpserver/wsgi.py
Sylvain Le Bon's avatar
Sylvain Le Bon committed
128

Calum Mackervoy's avatar
Calum Mackervoy committed
129
9. You will probably need to create a super user
Alexandre's avatar
Alexandre committed
130

131 132
```bash
$ ./manage.py createsuperuser
Alexandre's avatar
Alexandre committed
133
```
134

Calum Mackervoy's avatar
Calum Mackervoy committed
135
10. If you have no CSS on the admin screens :
136 137 138

```bash
$ ./manage.py collectstatic
Alexandre's avatar
Alexandre committed
139 140
```

Alexandre's avatar
Alexandre committed
141
## Execution
142

Alexandre's avatar
Alexandre committed
143
To start the server, `cd` to the root of your Django project and run :
144 145 146

```bash
$ python3 manage.py runserver
Alexandre's avatar
Alexandre committed
147 148
```

Sylvain Le Bon's avatar
Sylvain Le Bon committed
149
## Custom Parameters to LDPViewSet
Sylvain Le Bon's avatar
Sylvain Le Bon committed
150

Sylvain Le Bon's avatar
Sylvain Le Bon committed
151
### lookup_field
152

Sylvain Le Bon's avatar
Sylvain Le Bon committed
153
Can be used to use a slug in the url instead of the primary key.
154 155

```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
156 157 158 159
LDPViewSet.urls(model=User, lookup_field='username')
```

### nested_fields
160

Sylvain Le Bon's avatar
Sylvain Le Bon committed
161 162
list of ForeignKey, ManyToManyField, OneToOneField and their reverse relations. When a field is listed in this parameter, a container will be created inside each single element of the container.

163
In the following example, besides the urls `/members/` and `/members/<pk>/`, two other will be added to serve a container of the skills of the member: `/members/<pk>/skills/` and `/members/<pk>/skills/<pk>/`
Sylvain Le Bon's avatar
Sylvain Le Bon committed
164

165 166 167
```python
<Model>._meta.nested_fields=["skills"]
```
Benoit Alessandroni's avatar
Benoit Alessandroni committed
168

169 170 171
## Custom Meta options on models

### rdf_type
172

173
### auto_author
174

Alexandre's avatar
Alexandre committed
175 176
This property allows to associate a model with the logged in user.

177

Alexandre's avatar
Alexandre committed
178
```python
Alexandre's avatar
Alexandre committed
179 180 181 182
class MyModel(models.Model):
    author_user = models.ForeignKey(settings.AUTH_USER_MODEL)
    class Meta:
        auto_author = 'author_user'
Alexandre's avatar
Alexandre committed
183
```
184

Alexandre's avatar
Alexandre committed
185 186
Now when an instance of `MyModel` is saved, its `author_user` property will be set to the current user. 

187
## permissions_classes
188

189 190
This allows you to add permissions for anonymous, logged in user, author ... in the url:
By default `LDPPermissions` is used.
191 192
Specific permissin classes can be developed to fit special needs.

193
## anonymous_perms, user_perms, owner_perms
194 195

Those allow you to set permissions from your model's meta.
196

197
You can give the following permission to them:
198

199 200 201 202 203 204 205 206 207 208
* `view`
* `add`
* `change`
* `control`
* `delete`
* `inherit`

With inherit, Users can herit from Anons. Also Owners can herit from Users.

Eg. with this model Anons can view, Auths can add & Owners can edit & delete.
209

210 211
Note that `owner_perms` need a `owner_field` meta that point the field with owner user.

212 213 214 215 216 217
```python
from djangoldp.models import Model

class Todo(Model):
    name = models.CharField(max_length=255)
    deadline = models.DateTimeField()
218 219
    user = models.ForeignKey(settings.AUTH_USER_MODEL)

220
    class Meta:
221 222 223
        anonymous_perms = ['view']
        authenticated_perms = ['inherit', 'add']
        owner_perms = ['inherit', 'change', 'control', 'delete']
224
        owner_field = 'user'
225 226 227 228 229 230
```


Important note:
If you need to give permissions to owner's object, don't forget to add auto_author in model's meta

231 232
### view_set

233 234
In case of custom viewset, you can use 

235
```python
236 237 238 239 240 241 242 243 244 245 246
from djangoldp.models import Model

class Todo(Model):
    name = models.CharField(max_length=255)
    deadline = models.DateTimeField()
    
    class Meta:
        view_set =  TodoViewSet

```

247 248
### container_path

249 250
See 3.1. Configure container path (optional)

251 252 253
### serializer_fields

```python
254 255 256 257 258
from djangoldp.models import Model

class Todo(Model):
    name = models.CharField(max_length=255)
    deadline = models.DateTimeField()
259

260 261 262 263
    class Meta:
        serializer_fields =  ['name']

```
264

265
Only `name` will be serialized
266

267
## Custom urls
268

269 270
To add customs urls who can not be add through the `Model` class, it's possible de create a file named `djangoldp_urls.py`. It will be executed like an `urls.py` file

271
## Pagination
272

273 274
To enable pagination feature just add this configuration to the server `settings.py` :

275
```python
276
REST_FRAMEWORK = {
277
    'DEFAULT_PAGINATION_CLASS': 'djangoldp.pagination.LDPPagination',
278 279 280
    'PAGE_SIZE': 20
}
```
281

282
## Sources
283

284 285 286 287 288 289 290 291
To enable sources auto creation for all models, change `djangoldp` by `djangoldp.apps.DjangoldpConfig`, on `INSTALLED_APPS`

```python
INSTALLED_APPS = [
    'djangoldp.apps.DjangoldpConfig',
]
```

292
## 301 on domain mismatch
293

294
To enable 301 redirection on domain mismatch, add `djangoldp.middleware.AllowOnlySiteUrl` on `MIDDLEWARE`
295 296 297 298 299 300 301 302

This ensure that your clients will use `SITE_URL` and avoid mismatch betwen url & the id of a resource/container

```python
MIDDLEWARE = [
    'djangoldp.middleware.AllowOnlySiteUrl',
]
```
303

304 305
Notice tht it'll redirect only HTTP 200 Code.

Sylvain Le Bon's avatar
Sylvain Le Bon committed
306 307 308
## License

Licence MIT