1

I am building a simple app using User Authentication.

My app has 3 models:

  • Users : The standard Django user model
  • Locations: A model for an office (address, site name, etc)
  • Employees: A model for an employee (name, email, etc)

I also have a series of views that allow a user to login, create, and edit locations/sites, etc.

What I want to know, is what is the best practice to restrict editing of model instances to those which the user has created? E.g. with no amendment, two users could create data and both could edit the others. How do I restrict this to editing their own?

I know the long form way is to put a ForeignKey(User) on each model to restrict the view with a queryset, but this seems lengthy and cumbersome. Is there a Django trick I am missing? Perhaps a decorator?

What's the best practice?

alias51
  • 8,178
  • 22
  • 94
  • 166
  • If users are to only edit their own object, IanAuld's answer is the way to go. Otherwise you could have a set of users who could edit all objects, you could control this by putting these users in a group. – henrikstroem Aug 23 '15 at 10:05

1 Answers1

4

The easiest way would be to edit your models so that they have an owner or user field that is a ForeignKey to the creator.

class Locations(models.Model):
    owner = ForeignKey(User)
    ...

And in your views:

def edit_location(request, location_id):
    location = Locations.objects.get(pk=location_id)
    if request.user is not location.owner:
        # return a 401 or redirect to somewhere
    else:
        # do stuff

You can use Django's ManyToManyField option if each Location and User can have multiple relationships. For example:

class Locations(models.Model):
    owners = models.ManyToManyField(User)

user = User.objects.create(username='Ian')
location = Locations.objects.create(...)
location.owners.add(user)

And then the User/Locations are available on both:

>>> location.owners.all()
[<User: Ian>]
>>> user.locations_set.all()
[<Locations: ...>]

The set on User will be automatically created and it will be named <Model Name>_set.

You can then use the in operator to check ownership:

def edit_location(request, location_id):
        location = Locations.objects.get(pk=location_id)
        if request.user in location.owners.all():
            # return a 401 or redirect to somewhere
        else:
            # do stuff
kylieCatt
  • 10,672
  • 5
  • 43
  • 51
  • Thanks. Let's say I wanted to extend this, so that 2 users could edit the same data. Then a foreign key won't work (as this is 1-1). Any ideas? – alias51 Aug 23 '15 at 11:19
  • `ManyToManyField` should work assuming each `User` can have many `Locations` and each `Location` can have many `User`'s – kylieCatt Aug 23 '15 at 17:14