1

I'm working on a project using Python(3.7) and Django(2.3) in which I have implemented multiple types of users by extending the Base user model, now I need to create a UserEdit page to allow the staff to edit a user.

Here's my models:

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=254, unique=True)
    name = models.CharField(max_length=255)
    title = models.CharField(max_length=255, choices=TITLE, blank=False)
    user_type = models.CharField(max_length=255, choices=USER_TYPE, blank=False)
    gender = models.CharField(max_length=255, choices=CHOICES, blank=False)
    contenst = models.CharField(max_length=255, blank=True, null=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    email_status = models.CharField(max_length=50, default='nc')

    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = ['password']

    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % (self.pk)

    def __str__(self):
        return str(self.email)


class PersonalBelow18(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='profile')
    dob = models.DateField(blank=False)
    customer_id = models.IntegerField(blank=False, verbose_name='Connect other User')
    collection_use_personal_data = models.BooleanField(blank=False)
    reference_identities = models.ForeignKey(Identities, blank=False, on_delete=models.CASCADE, related_name='refs')

    def __str__(self):
        if self.user.email is None:
            return "ERROR-CUSTOMER NAME IS NULL"
        return str(self.user.email)

    GRAPPELLI_AUTOCOMPLETE_SEARCH_FIELDS = {
        "myapp": {
            "MyFile": ("user__email__icontains",)
        }
    }


class PersonalAbove18(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    dob = models.DateField(blank=False)
    customer_id = models.IntegerField(blank=False, verbose_name='Connect other User')
    contact_email = models.EmailField(max_length=255, blank=False)
    reference_identities = models.ForeignKey(Identities, blank=False, on_delete=models.CASCADE)
    contact_no = PhoneNumberField(blank=True, null=True, max_length=13,
                                  help_text='Phone number must be entered in the'
                                            'format: \'+999999999\'. Up to 13 digits allowed.')

    collection_use_personal_data = models.BooleanField(blank=False)

    def __str__(self):
        print(type(self.user.email))
        if self.user.email is None:
            return "ERROR-CUSTOMER NAME IS NULL"
        return str(self.user.email)


class ContactPerson(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    contact_email = models.EmailField(blank=False)
    customer_id = models.BigIntegerField(blank=True)
    contact_no = PhoneNumberField(blank=True, null=True, help_text='Phone number must be entered in the'
                                                                   'format: \'+999999999\'. Up to 15 digits allowed.')
    collection_use_personal_data = models.BooleanField(blank=False)


class GroupContact(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    contact_email = models.EmailField(blank=False)
    customer_id = models.BigIntegerField(blank=False)
    contact_no = PhoneNumberField(blank=True, help_text='Phone number must be entered in the'
                                                        'format: \'+999999999\'. Up to 15 digits allowed.')
    department = models.CharField(max_length=255, blank=False)
    address = models.CharField(max_length=255, blank=False)

and here's my forms:

class UserForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('email', 'name', 'password1', 'password2', 'title',
                  'gender', 'contenst', 'user_type')

   class Below18Form(forms.ModelForm):
    class Meta:
        model = PersonalBelow18
        widgets = {'dob': DateInput()}
        fields = ('dob', 'customer_id', 'collection_use_personal_data')

class Above18Form(forms.ModelForm):
    class Meta:
        model = PersonalAbove18
        widgets = {'dob': DateInput()}
        fields = ('dob', 'customer_id',
                  'contact_email',
                  'contact_no', 'collection_use_personal_data')

class UserCPForm(forms.ModelForm):
    class Meta:
        model = ContactPerson
        fields = ('contact_email', 'contact_no', 'collection_use_personal_data')

class GroupContactForm(forms.ModelForm):
    class Meta:
        model = GroupContact
        fields = ('contact_email', 'contact_no', 'department', 'address')

Here is the MultiModelForm I have used to combine multiple forms:

and here's my view:

class EditUserDashboard(generic.DetailView):
    def get(self, request, *args, **kwargs):
        id = self.kwargs['id']
        try:
            u = User.objects.get(id=id)
            print(u.user_type)
            u_form = UserForm(request.POST, instance=u)
            if u.user_type == 'PB':
                p = PersonalBelow18.objects.get(user_id=id)
                p_form = Below18Form(request.POST, instance=p)
                return render(request, 'dashboard/user_edit.html', {'u_form': u_form,
                                                                    'p_form': p_form,
                                                                    'u': u})
            elif u.user_type == 'PA':
                p = PersonalAbove18.objects.get(user_id=id)
                p_form = Above18Form(request.POST, instance=p)
                return render(request, 'dashboard/user_edit.html', {'u_form': u_form,
                                                                    'p_form': p_form,
                                                                    'u': u})
            elif u.user_type == 'ContactPerson':
                p = ContactPerson.objects.get(user_id=id)
                print(p.user.id)
                p_form = UserCPForm(request.POST, instance=p)
                return render(request, 'dashboard/user_edit.html', {'u_form': u_form,
                                                                    'p_form': p_form,
                                                                    'u': p})
            elif u.user_type == 'GC':
                p = GroupContact.objects.get(user_id=id)
                p_form = GroupContactForm(request.POST, instance=p)
                return render(request, 'dashboard/user_edit.html', {'u_form': u_form,
                                                                    'p_form': p_form,
                                                                    'u': u})
            else:
                print('something else')
        except Exception as e:
            print(e)
            pass

Update: My HTML form:

<form action="" method="post" class="form">
     {% csrf_token %}
     {{ u_form|crispy }}
     {{ p_form|crispy }}
     <button type="submit" class="btn btn-primary" value="update">Update</button>
</form>

when I load the edit page it returns the error as:

'ContactPerson' object is not subscriptable

Internal Server Error: /dashboard/user/10/edit Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner response = get_response(request) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response "returned None instead." % (callback.module, view_name) ValueError: The view dashboard.views.EditUserDashboard didn't return an HttpResponse object. It returned None instead. [21/Dec/2019 20:07:16] "GET /dashboard/user/10/edit HTTP/1.1" 500 53502

Abdul Rehman
  • 3,693
  • 1
  • 45
  • 106
  • @roganjosh I have added the view, error comes on the get request to `EditUserDashboard` – Abdul Rehman Dec 21 '19 at 12:12
  • Yep. What happens if your `try` fails in `class EditUserDashboard(generic.DetailView):`? Your `except Exception as e` should be printing something in the console, and you return `None` – roganjosh Dec 21 '19 at 12:13
  • yes, my exception statement is printing: `'ContactPerson' object is not subscriptable` – Abdul Rehman Dec 21 '19 at 12:41
  • @roganjosh I have updated the forms in `forms.py` and in `views` also, now it's loading the forms on get request but with empty fields, it should load the fields with populated data. – Abdul Rehman Dec 21 '19 at 12:55
  • @roganjosh see at https://stackoverflow.com/q/59442964/7644562 – Abdul Rehman Dec 22 '19 at 09:22

1 Answers1

1

You can try the following:

p = ContactPerson.objects.get(user__id=id)  # instead of user_id=id

or

p = ContactPerson.objects.get(user=u)
Pedram Parsian
  • 3,205
  • 3
  • 15
  • 29
rajjix
  • 161
  • 5
  • I have changed the statement to `p = ContactPerson.objects.get(user__id=id)` but still the same error. – Abdul Rehman Dec 21 '19 at 12:43
  • I have updated the forms in `forms.py` and in `views` also, now it's loading the forms on get request but with empty fields, it should load the fields with populated data. – Abdul Rehman Dec 21 '19 at 12:55
  • Good, Can you please show the related snippet inside user_edit.html. – rajjix Dec 21 '19 at 13:00
  • I have added the related HTML. – Abdul Rehman Dec 21 '19 at 13:17
  • Why do you have two separate forms in one form tag ?, this seems pretty odd to me. it's like your trying to do a formset which doesn't accept predefined instances but in an un-comprehended way (at least by me). My suggestion would be get rid of one form for now and use the p_form only both in views and templates, see if that works because single forms accepts instances as a parameter. If our approach works, you might want to use formsets to prepopulate multiple forms in one page. here's a link to another ST answer that gives a good overview on accomplishing this. – rajjix Dec 21 '19 at 14:02
  • https://stackoverflow.com/questions/1395807/proper-way-to-handle-multiple-forms-on-one-page-in-django#answer-17303425 – rajjix Dec 21 '19 at 14:04
  • Also u can use initial instead of instance then you would need to change your form instantiation to `UserCPForm(request.POST, initial=model_to_dict(p))`. – rajjix Dec 21 '19 at 14:08
  • I have tried even with the single form, it's not loading the data. – Abdul Rehman Dec 22 '19 at 06:09