permission: Design-Frage

Django, Flask, Bottle, WSGI, CGI…
Antworten
robin_
User
Beiträge: 17
Registriert: Montag 3. August 2020, 17:59

Donnerstag 22. Oktober 2020, 13:25

Hi,

ich bin gerade dabei mir die Logik für login/auth/permission (mit dem drf) anzueignen.

Nun möchte ich, aufbauend darauf, den Zugriff auf die Model-Struktur einschränken.
Ich habe ein Model mit dem Namen "Task" und möchte, dass nur der User, der es erstellt hat, auch wieder einsehen kann. Also ganz klassischer Anwendungsfall, dass man seinen eigenen Account hat und die gespeicherten Daten auch nur (nach login) von der Person eingesehen werden können.

Meine Frage:
Ich wollte das so lösen, dass quasi jedes Model ein Feld hat, welches auf den eingeloggten Benutzer zeigt.

Code: Alles auswählen

class Task(models.Model):
    name = models.CharField(max_length=100)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="tasks")
    
Dann würde ich in der View die tasks-Objekte so abfragen wollen:

Code: Alles auswählen

class TestView(APIView):
    authentication_classes=[TokenAuthentication]
    permission_classes=[IsAuthenticated]

    def get(self, request):
        user = request.user
        tasks = user.tasks.all()
        serializer = TaskSerializer(tasks, many=True)
        return Response(serializer.data)

Nun kriege ich dabei folgenden Fehler in der Console:

Code: Alles auswählen

Internal Server Error: /api/test
Traceback (most recent call last):
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\sqlite3\base.py", line 413, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: core_task.user_id

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\core\handlers\base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\views\generic\base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\Robin\django\authtest\myapi\core\views.py", line 47, in post
    serializer.save()
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\serializers.py", line 205, in save
    self.instance = self.create(validated_data)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\serializers.py", line 939, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\query.py", line 447, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 753, in save
    self.save_base(using=using, force_insert=force_insert,
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 790, in save_base
    updated = self._save_table(
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 895, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 933, in _do_insert
    return manager._insert(
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\query.py", line 1254, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\sql\compiler.py", line 1397, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 98, in execute
    return super().execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\sqlite3\base.py", line 413, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: core_task.user_id
[22/Oct/2020 14:21:21] "POST /api/test HTTP/1.1" 500 184341
Unauthorized: /api/test
[22/Oct/2020 14:21:35] "POST /api/test HTTP/1.1" 401 58
Internal Server Error: /api/test
Traceback (most recent call last):
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\sqlite3\base.py", line 413, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: core_task.user_id

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\core\handlers\base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\views\generic\base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\Robin\django\authtest\myapi\core\views.py", line 47, in post
    serializer.save()
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\serializers.py", line 205, in save
    self.instance = self.create(validated_data)
  File "C:\Users\Robin\django\authtest\lib\site-packages\rest_framework\serializers.py", line 939, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\query.py", line 447, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 753, in save
    self.save_base(using=using, force_insert=force_insert,
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 790, in save_base
    updated = self._save_table(
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 895, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\base.py", line 933, in _do_insert
    return manager._insert(
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\query.py", line 1254, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\models\sql\compiler.py", line 1397, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 98, in execute
    return super().execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Robin\django\authtest\lib\site-packages\django\db\backends\sqlite3\base.py", line 413, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: core_task.user_id
[22/Oct/2020 14:21:39] "POST /api/test HTTP/1.1" 500 184341

Viel wichtiger als die Behebung des Fehlers wäre mir aber die Frage, ob es Design-technisch sinnvoll ist, den Zugriff entsprechend einzuschränken? Also, dass jedes Model-Objekt ein Feld auf den User kriegt um damit nur die Objekte zu filtern, welche dem entsprechenden User zugeordnet sind. Ist dieses Vorgehen gut oder sollte man was gänzlich anderes machen? Unter welchem Suchbegriff finde ich dazu mehr?

Danke!
Bolitho
User
Beiträge: 174
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Samstag 21. November 2020, 15:24

Du hast die Lösung sicher längst, aber vielleicht hat ja mal jemand ein ähnliches Problem.

In deinem Test wurde das Feld "User" im Model "Task" nicht eingetragen und da es aber nicht "NULL" sein darf, wirft Django den Fehler. Wenn du einen User als Besitzer einträgst, kommt der Fehler nicht. Oder du änderst das Model und erlaubst auch Tasks ohne User (blank=True, null=True). Denke aber, die erste Variante ist für deinen Fall passend.

Designtechnisch halte ich es für sinnvoll und setze es auch regelmäßig in dieser Form um.
Antworten