Search code examples
pythondjangodjango-admindjango-database

Django Admin not saving data to the Database


I am trying to save data from my Django Admin to my database but somehow it is not happening. I have created a form in one of my apps which my admin uses.I am new to Django and any help would be greatly appreciated. Below is the relevant code:

models.py

from __future__ import unicode_literals
from django.contrib.auth.models import User
from django_countries.fields import CountryField
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    name = models.CharField(max_length=100)
    bio = models.TextField(max_length=1000, blank=True, null=True)
    image = models.FileField()
    country = CountryField()
    city = models.CharField(max_length=100)
    twitter = models.CharField(max_length=100, null=True, blank=True)
    linkedin = models.CharField(max_length=100, null=True, blank=True)
    location = models.TextField()

    def __unicode__(self):
        return self.name

    def __str__(self):
        return self.name


class Mentor(models.Model):
    mentor = models.CharField(max_length=100)
    mentee = models.CharField(max_length=100)

    def __unicode__(self):
        return self.mentee

    def __str__(self):
        return self.mentee

forms.py

from django import forms
from models import UserProfile, Mentor
from django_countries.fields import CountryField
from django.contrib.auth.models import User
from reports.models import Reports

class UserProfileForm(forms.ModelForm):

    name = forms.CharField(max_length=100)
    bio = forms.Textarea()
    image = forms.FileField(label='Profile Photo')
    country = CountryField(blank_label='(Select Country)')
    city = forms.CharField(max_length=100)
    twitter = forms.CharField(max_length=100, required=False)
    linkedin = forms.CharField(max_length=100, required=False)

    class Meta:
        model = UserProfile
        exclude = ('user',)

class MentorForm(forms.ModelForm):
    mentor_choices = tuple(UserProfile.objects.filter(user__is_staff=1).order_by('name').values_list('name', 'name'))
    mentee_choices = tuple(UserProfile.objects.exclude(user__is_staff=1).order_by('name').values_list('name', 'name'))
    mentor_name = forms.ChoiceField(choices=mentor_choices)
    mentee_name = forms.ChoiceField(choices=mentee_choices)

    def save(self, commit=True):
        mentor_name = self.cleaned_data.get('mentor_name', None)
        mentor_name = self.cleaned_data.get('mentee_name', None)
        return super(MentorForm, self).save(commit=commit)

    class Meta:
        model = Mentor
        fields= ('mentor_name', 'mentee_name')

admin.py

from django.contrib import admin
from .models import UserProfile, Mentor
from.forms import MentorForm

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('user',)
    search_fields = ['user']

    def save_model(self, request, obj, form, change):
        obj.created_by = request.user
        obj.save()
admin.site.register(UserProfile, UserProfileAdmin )

class MentorAdmin(admin.ModelAdmin):
    list_display = ('__unicode__','mentee')
    search_fields = ['mentee', 'mentor']
    form = MentorForm

    fieldsets = (
        (None,{
            'fields': ('mentor_name', 'mentee_name'),
        }),
    )

    def save_model(self, request, obj, form, change):
        super(MentorAdmin, self).save_model(request, obj, form, change)

admin.site.register(Mentor, MentorAdmin )

The UserProfile works perfectly but the Mentor form in admin doesn't save anything in the database. It creates blank entries into the database, so I know that the front and backend are talking but no data is being passed. Any help will be very helpful


Solution

  • def save(self, commit=True):
        # here you define `mentor_name`. OK.
        mentor_name = self.cleaned_data.get('mentor_name', None)
        # here you redefine `mentor_name`. I guess it is a typo and should be `mentee_name`.
        mentor_name = self.cleaned_data.get('mentee_name', None)
        # And... you don't do anything with these variables.
        return super(MentorForm, self).save(commit=commit)
    

    This method is equivalent to:

    def save(self, commit=True):
        return super(MentorForm, self).save(commit=commit)
    

    Which is equivalent to not overriding the save method at all.

    And what about this?

    def save_model(self, request, obj, form, change):
        super(MentorAdmin, self).save_model(request, obj, form, change)
    

    What is the purpose of overriding a method and only calling the parent method with the exact same arguments?

    But the actual issue is here:

    mentor_choices = tuple(UserProfile.objects.filter(user__is_staff=1).order_by('name').values_list('name', 'name'))
    mentee_choices = tuple(UserProfile.objects.exclude(user__is_staff=1).order_by('name').values_list('name', 'name'))
    mentor_name = forms.ChoiceField(choices=mentor_choices)
    mentee_name = forms.ChoiceField(choices=mentee_choices)
    
    class Meta:
        model = Mentor
        fields = ('mentor_name', 'mentee_name')
    

    You use a ModelForm but none of the Mentor's fields is in fields. What are you expecting this to do other than saving a row with Mentor.mentor = None and Mentor.mentee = None. You don't even mention those fields.

    And why are you using CharField for Mentor.mentor and Mentor.mentee while you likely want a foreign key.

    class Mentor(models.Model):
        mentor = models.ForeignKey(UserProfile, models.PROTECT,
                                   related_name='mentees')
        mentee = models.ForeignKey(UserProfile, models.PROTECT,
                                   related_name='mentors')
    
    class MentorForm(forms.ModelForm):
    
        class Meta:
            model = Mentor
            fields = ('mentor', 'mentee')
    
        mentor = forms.ModelChoiceField(queryset=UserProfile.objects.filter(
            user__is_staff=True).order_by('name'))
        mentee = forms.ModelChoiceField(queryset=UserProfile.objects.exclude(
            user__is_staff=True).order_by('name'))
    

    Or even better:

    class Mentor(models.Model):
        mentor = models.ForeignKey(
            UserProfile, models.PROTECT, related_name='mentees',
            limit_choices_to={'user__is_staff': True},
        )
        mentee = models.ForeignKey(
            UserProfile, models.PROTECT, related_name='mentors',
            limit_choices_to={'user__is_staff': False},
        )
    

    Which avoids you to create a form.