Django Modelform OneToOneFielld - python

I'm currently writing a system in Django where I'd like to save a user at the same time i'm creating another model.
Model Code:
class MyModel(models.Model):
user = models.OneToOneField(User,related_name="profile",primary_key=True)
custom_field = models.CharField(...)
The model is more elaborate of course, but it shows the setup of the whole thing.
Example form:
First name: [input]
Last name: [input]
Email: [input]
Password: [pass_input]
Custom Text: [text_input]
Is this at all possible using a ModelForm?

Yes; you could create a ModelForm that corresponds to MyModel:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['custom_field']
Then in your view, you could interrupt the save of this form using commit=False (https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#the-save-method) and set the user value of your new object manually. For example, you could set user = request.user like so:
if form.is_valid():
instance = form.save(commit = False)
instance.user = request.user
instance.save()
form.save_m2m() #if your form has any m2m data to save

Yes. In your forms.py file, add this code:
class UserForm(ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(ModelForm):
class Meta:
model = MyModel
fields = ('customfield1', 'customfield2')
EDIT
Here is a great tutorial on to do this: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html

Related

Django REST: Custom field, list may not be empty

I'm trying to add the employees field to my custom user model in Django REST 2.2. This is how I implemented my custom user (first answer). The employees field is just a list of custom users (so it's related to itself, with a many-to-many relationship).
When I try to add a custom user model from the django interface, it says "this list may not be empty". How can I make it so it can be empty? I thought that's what I added "required=False" for.
users/models.py
class CustomUser(AbstractUser):
employees = models.ManyToManyField("self", related_name='employees')
users/serializers.py (CustomRegisterSerializer is used for registering with rest-auth, CustomUserSerializer is used to view and edit)
class CustomRegisterSerializer(RegisterSerializer):
employees = serializers.RelatedField(many=True, required=False, queryset=CustomUser.objects.all())
def get_cleaned_data(self):
data_dict = super().get_cleaned_data()
data_dict['employees'] = self.validated_data.get('employees', '')
return data_dict
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email', 'employees')
users/views.py
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer

How to change djangos default User Creation Form

I extended the Django User Model and added a required ForeignKeyField called company. Now I also need to Change the default user creation Form. What I tried so far was:
Creating a new Form that Inherits from the default UserCreationForm form:
class MyUserCreationForm(UserCreationForm):
company = forms.ModelChoiceField(queryset=Company.objects.all())
class Meta:
model = MyUser
fields = ('username', 'company')
Adding it to my extended Django Admin:
class ExtendedUserAdmin(UserAdmin):
add_form = MyUserCreationForm
...
admin.site.register(MyUser, ExtendedUserAdmin)
This does not work. What am I missing?
Turns out you don't need to change add_form. All you need to do is add the following to ExtendedUserAdmin:
def __init__(self, model, admin_site):
super().__init__(model, admin_site)
self.add_fieldsets[0][1]['fields'] = ('username', 'password1', 'password2', 'company')

How I can send JSON on Django request to create a new User and Profile?

From django rest framework site examples I write my UserSerializer.py and my ProfileSerializer is like that:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['facebook_id', 'facebook_token', 'push_device_token', 'photo', 'status', 'level']
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ('username', 'email', 'profile')
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
And I'am sending JSON request like this:
{
"username":"admin",
"email":"e#e.com",
"password":12345678,
"profile":{
"status":1,
"level":1,
"facebook_id":1,
"facebook_token":1,
"push_device_token":1,
"photo":"url.com"
}
}
But I only get the error:
Got AttributeError when attempting to get a value for field profile on serializer UserSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'profile'.
I think it could be the lack of reference to the User model. Let's say your Profile model looks like this:
class Profile(models.Model):
user = models.ForeignKey(User)
The model User will have a profile_set attribute and not profile. To adjust this use the related_name:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile')

How to serialize the return value of a method in a model?

I have a Django app that uses Django REST Framework and Django-allauth. Now, I'm trying to retrieve the avatar URL that's present in the social account. However, I'm having trouble forming the serializer.
For background info, the allauth's SocialAccount is related to the user model via a foreign key:
class SocialAccount(models.Model):
user = models.ForeignKey(allauth.app_settings.USER_MODEL)
# the method I'm interested of
def get_avatar_url(self):
...
Now, here's the serializer I currently have:
class ProfileInfoSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name', 'last_name')
In the end, I'd like to have an extra field avatar_url which takes the result of the method call in the SocialAccount model. How do I do that?
I found a solution using a SerializerMethodField:
class ProfileInfoSerializer(serializers.ModelSerializer):
avatar_url = serializers.SerializerMethodField()
def get_avatar_url(obj, self):
return obj.socialaccount_set.first().get_avatar_id()
class Meta:
model = User
fields = ('id', 'first_name', 'last_name', 'avatar_url')

How to save a field after commit=False with model Form in Django?

I have a model:
class Book(models.Model):
name = models.CharField(max_length=100)
alias = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return self.name
and a ModelForm in forms.py:
class BookForm(ModelForm):
class Meta:
model = Book
So I'm trying to make something like this in my views:
def register_book(request):
if request.method == 'POST':
formul = BookForm(request.POST)
if formul.is_valid():
new_book=formul.save(commit=False)
new_book.alias='foo'
new_book.save()
return HttpResponseRedirect('/')
So, I'm saving from a html "form" the name & description, but the alias I need to save after I get the form. But isn't working.
A ModelForm will by default include and validate all fields of the model. If you always assign the alias value yourself in the view, then you don't need the alias field in the form and you can just exclude it:
class BookForm(ModelForm):
class Meta:
model = Book
fields = ('name', 'description')
# NOTE: you can also use excludes, but many consider it a bad practice
As always, Django docs can tell you more about it.
You're trying to save the model without an alias first. You need to allow blank values before you can do that. The recommended approach would be using blank:
alias = models.CharField(max_length=100, blank=True)

Categories