README.md 6.81 KB
Newer Older
Sylvain Le Bon's avatar
Sylvain Le Bon committed
1 2 3 4 5 6 7 8 9 10 11
## 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.

## Requirements

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

## Installation

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

19 20
```bash
$ pip install djangoldp
Sylvain Le Bon's avatar
Sylvain Le Bon committed
21 22
```

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

Benoit Alessandroni's avatar
Benoit Alessandroni committed
29
3. Create your django model inside a file myldpserver/myldpserver/models.py
30 31
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
32

33
```python
34
from djangoldp.models import Model
Sylvain Le Bon's avatar
Sylvain Le Bon committed
35

36
class Todo(Model):
Sylvain Le Bon's avatar
Sylvain Le Bon committed
37 38 39 40
    name = models.CharField(max_length=255)
    deadline = models.DateTimeField()
```

41 42 43
3.1. Configure container path (optional)
By default it will be "todos/" with an S for model called Todo

44
```python
45 46 47 48
<Model>._meta.container_path = "/my-path/"
```

3.2. Configure field visibility (optional) 
49 50
Note that at this stage you can limit access to certain fields of models using

51
```python
52 53 54 55 56 57 58
<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.

59
```python
60 61 62 63 64
from django.contrib.auth.models import User

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

65 66
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.

Benoit Alessandroni's avatar
Benoit Alessandroni committed
67
4. Add a url in your urls.py:
Alexandre's avatar
Alexandre committed
68

69
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
70 71
from django.conf.urls import url
from django.contrib import admin
Sylvain Le Bon's avatar
Sylvain Le Bon committed
72
from djangoldp.views import LDPViewSet
Sylvain Le Bon's avatar
Sylvain Le Bon committed
73
from .models import Todo
Sylvain Le Bon's avatar
Sylvain Le Bon committed
74 75

urlpatterns = [
76 77
    url(r'^', include('djangoldp.urls')),
    url(r'^admin/', admin.site.urls), # Optional
Sylvain Le Bon's avatar
Sylvain Le Bon committed
78 79
]
```
Alexandre's avatar
Alexandre committed
80

81 82 83 84
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:

85
```python
86 87
ROOT_URLCONF = 'djangoldp.urls'
```
Sylvain Le Bon's avatar
Sylvain Le Bon committed
88

Benoit Alessandroni's avatar
Benoit Alessandroni committed
89
5. 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
90

91
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
92 93 94 95
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static')
LDP_RDF_CONTEXT = 'https://cdn.happy-dev.fr/owl/hdcontext.jsonld'
```

Benoit Alessandroni's avatar
Benoit Alessandroni committed
96
6. You can also register your model for the django administration site
Sylvain Le Bon's avatar
Sylvain Le Bon committed
97

98
```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
99 100 101 102 103 104
from django.contrib import admin
from .models import Todo

admin.site.register(Todo)
```

Benoit Alessandroni's avatar
Benoit Alessandroni committed
105
7. You then need to have your WSGI server pointing on myldpserver/myldpserver/wsgi.py
Sylvain Le Bon's avatar
Sylvain Le Bon committed
106

Benoit Alessandroni's avatar
Benoit Alessandroni committed
107
8. You will probably need to create a super user
Alexandre's avatar
Alexandre committed
108

109 110
```bash
$ ./manage.py createsuperuser
Alexandre's avatar
Alexandre committed
111
```
112 113 114 115 116

9. If you have no CSS on the admin screens :

```bash
$ ./manage.py collectstatic
Alexandre's avatar
Alexandre committed
117 118
```

Alexandre's avatar
Alexandre committed
119
## Execution
120

Alexandre's avatar
Alexandre committed
121
To start the server, `cd` to the root of your Django project and run :
122 123 124

```bash
$ python3 manage.py runserver
Alexandre's avatar
Alexandre committed
125 126
```

Sylvain Le Bon's avatar
Sylvain Le Bon committed
127
## Custom Parameters to LDPViewSet
Sylvain Le Bon's avatar
Sylvain Le Bon committed
128

Sylvain Le Bon's avatar
Sylvain Le Bon committed
129
### lookup_field
130

Sylvain Le Bon's avatar
Sylvain Le Bon committed
131
Can be used to use a slug in the url instead of the primary key.
132 133

```python
Sylvain Le Bon's avatar
Sylvain Le Bon committed
134 135 136 137
LDPViewSet.urls(model=User, lookup_field='username')
```

### nested_fields
138

Sylvain Le Bon's avatar
Sylvain Le Bon committed
139 140
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.

141
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
142

143 144 145
```python
<Model>._meta.nested_fields=["skills"]
```
Benoit Alessandroni's avatar
Benoit Alessandroni committed
146

147 148 149
## Custom Meta options on models

### rdf_type
150

151
### auto_author
152

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

155

Alexandre's avatar
Alexandre committed
156
```python
Alexandre's avatar
Alexandre committed
157 158 159 160
class MyModel(models.Model):
    author_user = models.ForeignKey(settings.AUTH_USER_MODEL)
    class Meta:
        auto_author = 'author_user'
Alexandre's avatar
Alexandre committed
161
```
162

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

165
## permissions_classes
166

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

171
## anonymous_perms, user_perms, owner_perms
172 173

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

175
You can give the following permission to them:
176

177 178 179 180 181 182 183 184 185 186
* `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.
187

188 189
Note that `owner_perms` need a `owner_field` meta that point the field with owner user.

190 191 192 193 194 195
```python
from djangoldp.models import Model

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

198
    class Meta:
199 200 201
        anonymous_perms = ['view']
        authenticated_perms = ['inherit', 'add']
        owner_perms = ['inherit', 'change', 'control', 'delete']
202
        owner_field = 'user'
203 204 205 206 207 208
```


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

209 210
### view_set

211 212
In case of custom viewset, you can use 

213
```python
214 215 216 217 218 219 220 221 222 223 224
from djangoldp.models import Model

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

```

225 226
### container_path

227 228
See 3.1. Configure container path (optional)

229 230 231
### serializer_fields

```python
232 233 234 235 236
from djangoldp.models import Model

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

238 239 240 241
    class Meta:
        serializer_fields =  ['name']

```
242

243
Only `name` will be serialized
244

245
## Custom urls
246

247 248
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

249
## Pagination
250

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

253
```python
254
REST_FRAMEWORK = {
255
    'DEFAULT_PAGINATION_CLASS': 'djangoldp.pagination.LDPPagination',
256 257 258
    'PAGE_SIZE': 20
}
```
259

260
## Sources
261

262 263 264 265 266 267 268 269
To enable sources auto creation for all models, change `djangoldp` by `djangoldp.apps.DjangoldpConfig`, on `INSTALLED_APPS`

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

Jean-Baptiste Pasquier's avatar
Jean-Baptiste Pasquier committed
270
## 302 on domain mismatch
271

Jean-Baptiste Pasquier's avatar
Jean-Baptiste Pasquier committed
272
To enable 302 redirection on domain mismatch, add `djangoldp.middleware.AllowOnlySiteUrl` on `MIDDLEWARE`
273 274 275 276 277 278 279 280

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',
]
```
281

Sylvain Le Bon's avatar
Sylvain Le Bon committed
282 283 284
## License

Licence MIT