Home > Enterprise >  Users to see only their objects in Django
Users to see only their objects in Django

Time:03-10

So I have an application where users can create their own Companies. But what I want in the view is for them to see only their entries on the view. I have seen similar questions on this platform but they don't work as expected. Below is my code.

Models.Py

from django.contrib.auth.models import User

class Company (models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    company_name = models.CharField(max_length=100, null=True)
    mailing_address = models.CharField(max_length=100, null=True)
    physical_address =  models.CharField(max_length=100, null=True)

class Meta:
    verbose_name_plural = "Companies"

def __str__(self):
    return self.company_name

views.py

@login_required(login_url='login')
def company (request):
    all_companies = Company.objects.filter(user=request.user)
    count= Company.objects.all().count()
    context = {'all_companies': all_companies, 'count': count}
    return render(request, 'company/company.html', context)

forms.py

class CompanyForm(forms.ModelForm):

def __init__(self, *args, **kwargs):
    super(CompanyForm, self).__init__(*args, **kwargs)

    self.fields['company_name'].widget.attrs = {'class': 'input',}
    self.fields['date_created'].widget.attrs = {'class': 'input',}
    self.fields['mailing_address'].widget.attrs = {'class': 'input',}
    self.fields['physical_address'].widget.attrs = {'class': 'input',}
    
class Meta:
    model = Company
    fields = ('company_name', 'date_created', 'mailing_address', 'physical_address',)

The so largely this works to ensure that every user only sees the company they have created. However, I can successfully create the companies from the admin side but a glaring issue appears. I have to manually select users from the form field = users in the admin form as shown in the picture below, to be able to create and save companies. It is the same behaviour on the front end with the form. This doesn't look right.

How can I ensure a company automatically points to the owner (user) who created it, without having to manually force the form to choose the user.

admin page

CodePudding user response:

If you want the user to be added automatically in Django admin, you can override the save_model of its corresponding ModelAdmin: https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model

If you want it to be populated when users are creating companies using forms, you can set the user attribute like this:

# assuming request.user is available
company_form = form.save(commit=False)
company_form.user = request.user
company_form.save()

CodePudding user response:

Since, user is the foreign key. You can take advantage of

'formfield_for_foreignkey' method in the ModelAdmin class.

This method gets executed for the foreign fields declared in the model. Here, we can check whether it has been executed for the user or not if yes, then we can prepopulate its value. You can customize the admin form by creating ModelAdmin class in admin.py for the Company model

@admin.register(Company)
class CompanyAdmin(admin.ModelAdmin):
    form = CompanyForm

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'user':
            kwargs['initial'] = request.user.id
            return db_field.formfield(**kwargs)

        return super(CompanyAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

In the ModelAdmin class you can specify the form class for further customizations.

Note, this will only prepopulate the value, the value of the user can be changed in the form. To avoid this, you can make user field uneditable and readonly field.

CodePudding user response:

So I finally found the solution, at least for the user field in the Company form.

This gives a clear way of doing this: https://docs.djangoproject.com/en/4.0/topics/class-based-views/generic-editing/#models-and-request-user

views.py: I added form.instance for the field user to ensure it picks the current user and feeds it in the form.

def company_form (request):
form = CompanyForm()
if request.method == 'POST':
    # Request files helps upload other files such as images
    form = CompanyForm(request.POST, request.FILES) 
    #This automatically inserts the user without exposing the form field
    form.instance.user = request.user 
  
    if form.is_valid():
        form.save() 
    return redirect('company')

Then I modified the model field for the user to ensure it is not editable.

models.py

class Company (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, editable=False)

This ensured no one can edit the user including the admin. That ideally solves 90 percent of my issues.

Appreciate everyone's help on this.

  • Related