Why are we inheriting here in django? - django

This is my first post here. I am a beginner in django and I am almost done reading through django for beginners by William S. Vincent. In chapter 8, he goes over the custom user model and creates the following code for the forms needed:
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = UserCreationForm.Meta.fields + ("age",)
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
My question is why are we using class Meta here and why is the first class Meta inheriting from "UserCreationForm", but the second class Meta doesn't. Thanks!

My question is why are we using class Meta here and why is the first class Meta inheriting from "UserCreationForm", but the second class Meta doesn't.
Likely that is a typo, it should be:
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta): # šŸ–˜ inherit from the Meta innerclass
model = CustomUser
fields = UserCreationForm.Meta.fields + ('age',)
It is usually a good idea to always inerhit from the Meta of the superclass, since it will for example in this case also include the field_classes attributeĀ [GitHub]:
class Meta:
model = User
fields = ("username",)
field_classes = {"username": UsernameField}
It here thus adds a specific field class for username, not the default CharField. If we want that behavior to continue, then we will need to inherit this, otherwise our Meta has no such field_classes item, and it will thus "fallback" on a simple CharField.
The latter was better with a simple:
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = CustomUser
since for modern versions of Django, it will make use of the UsernameField field class as well.

Related

Django child models don't inherit Meta inner class

I have two Django 3.0 models, one of which is a subclass of the other:
# models.py
class BaseCategory(models.Model):
class Meta:
verbose_name_plural = "categories"
class Category(BaseCategory):
# fields 'n' stuff
Only the Category model is registered in the Admin
# admin.py
#admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
# stuff here
In the Admin, the Category model is labeled "Categorys", despite the fact that it should have inherited the Meta inner class and its verbose_name_plural attribute from BaseCategory. In fact, if I copy the same code into the Category model,
# models.py
class Category(BaseCategory):
class Meta:
verbose_name_plural = "categories"
# fields 'n' stuff
the model is correctly labeled "Categories" in the Admin. This indicates that the Category class is not inheriting the Meta inner class of BaseCategory.
Why does a child class not inherit the Meta inner class? Is there another way for me to only specify verbose_name_plural once instead of copying the exact same code into every child of BaseCategory?
According to the Django Docs you need to declare the BaseCategory model abstract in order for its Meta class to be inherited.
class BaseCategory(models.Model):
class Meta:
abstract = True
verbose_name_plural = "categories"
The Category class will then automatically inherit the Meta class, except for the abstract attribute.
Note that if you want to make any changes to the Meta class in Category you need to subclass it explicitly:
class Category(BaseCategory):
class Meta(BaseCategory.Meta):
...

How to customize Django ModelForm fields?

Hi I am trying to customize my ModelForm in Django. The form looks like this:
class RegistrationForm(forms.ModelForm):
class Meta:
model = Registration
fields = ['name', 'age', 'details'......]
I am trying to add different classes to different fields, along with placeholders and no labels. How do I do that? Is there a way to carry this out in the templates?
You can add class and other parameters to a field using widget
class RegistrationForm(forms.ModelForm):
name = forms.CharField(label=' ',widget=forms.TextInput(attrs={'class':'textClass','placeholder':'Enter Name'}))
details = forms.CharField(widget=forms.Textarea(attrs={'class':'special','maxlength':'100'}))
class Meta:
model = Registration
fields = ['name', 'age', 'details'......]
For brief explanation: Documentation

Extending User fields in UserCreationForm

I am trying to add some custom fields to a user, and extend the UserCreationForm so that I can add these fields when the user is created. I am following the docs but when I try to load the page to create a user I get an error: Unknown field(s) (username) specified for Customer.
The docs that I am following: Custom User and Auth Forms
models.py
class User(AbstractUser):
is_restaurant = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
class Customer(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
def __str__(self):
return self.user.get_full_name()
forms.py
class CustomerSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = Customer
fields = UserCreationForm.Meta.fields + ('address',)
I understand that username is not part of the Customer class, but the docs appear to be doing the same thing...
The doc says:
If your custom user model is a simple subclass of AbstractUser, then
you can extend these forms in this manner...
In other words this will work only in case you want to add to the form is_restaurant or is_customer fields:
class CustomerSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('is_restaurant',)
But in your case Customer is not subclass of AbstractUser, since this method is not working for you. As a workaround you can try to work with two separate forms in the same time as suggested in this answer.

djangrestframework to display model in foreign key

Please excuse the title. Im not quite sure how ask this question without just showing.
In django I have two models.
class people(models.Model):
name=models.TextField(max_length=100)
nickname=models.TextField(max_length=100)
class visits(models.Model):
person=models.OneToOneField(people)
visitdate=models.DateTimeField(auto_now=True)
and then a serializer for the restapi.
#serializers.py
class VisitsSerializer(serializers.ModelSerializer):
class Meta:
model = visits
fields=("id","person","date")
When the API returns the dictionary, it looks like this.
{id:1,person:1,visitdate:11/23/17}
Is there a way to make the API return the actual values that are associated with the person with id 1? like so.
{id:1,person:{id:1,name:foo,nickname:bar},visitdate:11/23/17}
Try creating a serializer class for People and then add this to your visit serializer:
people = PeopleSerializer(read_only = True)
then add it(people) to fields in the Meta class, and just a suggestion, try making it a foreign key instead of a OnetoOne Relationship
You can do that with nested relationship. Here is an example:
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = people
fields = ('name', 'nickname')
class VisitsSerializer(serializers.ModelSerializer):
person = PersonSerializer(read_only=True)
class Meta:
model = visits
fields = ("id", "person", "date")
Documentation on nested serializers is here.
The Corresponding Serializer would be as follows:
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = people
class VisitsSerializer(serializers.ModelSerializer):
person = serializers.SerializerMethodField()
class Meta:
model = visits
fields = ('id', 'person', 'date')
def get_person(self, obj):
return PersonSerializer(obj.person).data

Restricted set of nested fields in a django REST framework ModelSerializer

Consider the following serializer
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'account')
depth = 1
The field account refers to a ForeignKey in MyModel and I want to expose some of the Account fields with this serializer but not all of them.
How do I specify that only account.name and account.email should be serialized?
You can do this by creating your own serializer to use as the nested serializer.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('name', 'email', )
You are better off with creating specialized serializers instead of relying on Django REST Framework to create them for you. By default, serializers that are automatically created contain all fields defined on the model.
class MyModelSerializer(serializers.ModelSerializer):
account = AccountSerializer()
class Meta:
model = MyModel
fields = ('id', 'account', )
You can find out more about nested serializers in the Django REST Framework documentation.