I have the following model
class Organizer(models.Model):
name = models.CharField(max_length=100)
phone = models.CharField(max_length=20, default="", blank=True)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
I have a field created_by of all the users. I don't want to show on the front end in admin form during adding form. how to do that. and save the current login user id
You need to add an admin form in admin.py and register that form to the model:
admin.py:
class OrganizerAdmin(admin.ModelAdmin):
fields = ('name', 'phone', 'created_at')
admin.site.register(Organizer, OrganizerAdmin)
you can read more about fields in admin page here
for hiding created_by
class OrganizerAdmin(admin.ModelAdmin):
// show fileds on form
fields = ('name', 'phone', 'created_at')
admin.site.register(Organizer, OrganizerAdmin)
and for save login user
def save_model(self, request, instance, form, change):
user = request.user
instance = form.save(commit=False)
if not change or not instance.created_by:
instance.created_by = user
instance.modified_by = user
instance.save()
form.save_m2m()
return instance
Related
I've two models:
class User(models.Model):
name = models.CharField(max_length=255)
email = models.EmailFeild()
password = models.CharField(max_length=255)
class Profile(models.Model):
user = models.ForeignKeyField(User, on_delete=models.CASCADE)
image = models.ForeignKeyField(to='media.images', on_delete=models.CASCADE)
mobile = models.IntegerField()
address = models.CharField(max_length=255)
Now I'm creating a patch API for updating profile. Now, a user can also update email and his name.
class ProfileUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
def update(self, instance, validated_data):
.........
How would I accept the User model's detail (email and name) in the profile payload and update both the models in my serializer?
At it simplest form, you can add two custom fields in the serializer:
class ProfileUpdateSerializer(serializers.ModelSerializer):
name = serializers.CharField()
email = serializers.EmailField()
And rewrite the serializer like this:
def update(self, instance, validated_data):
name = validated_data.pop('name', '')
email = validated_data.pop('email', '')
instance = super().update(instance, validated_data)
instance.user.email = email
instance.user.name = name
instance.user.save()
return instance
During serialization, i noticed that the post_author Foreign Key of the Post model is referencing the id of the creator and thus, i can't display the username of the creator in the REST API, only the post_author id.
How can i add the username of the post_creator, so that it is readable to other users, when i fetch the data on the frontend?
models.py // CustomUser = the Creator of the post.
class CustomUser(AbstractUser):
fav_color = models.CharField(blank=True, max_length=120)
class Post(models.Model):
post_author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='posts')
post_title = models.CharField(max_length=200)
post_body = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.post_title
views.py
#api_view(['GET'])
def post_list(request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response(serializer.data)
serializers.py user model and post model serialization
class CustomUserSerializer(serializers.ModelSerializer):
"""
Currently unused in preference of the below.
"""
email = serializers.EmailField(required=True)
username = serializers.CharField()
password = serializers.CharField(min_length=8, write_only=True)
class Meta:
model = CustomUser
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop('password', None)
# as long as the fields are the same, we can just use this
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
single post from the API
{
"id": 1,
"post_title": "first_post",
"post_body": "qwe1",
"created_date": "2020-11-17T19:30:55Z",
"published_date": null,
"post_author": 1
},
You need to override the serializer:
class PostSerializer(serializers.ModelSerializer):
post_author_username = serializers.ReadOnlyField(source="post_author.username")
class Meta:
model = Post
fields = [post_author_username, post_title, post_body, created_data, published_data]
You can to specify the post_author serializer in your PostSerializer:
class PostSerializer(serializers.ModelSerializer):
post_author=CustomUserSerializer(read_only=True)
class Meta:
model = Post
fields = '__all__'
You can see the documentation here
I have two models, Contact and User:
class Contact(models.Model):
name = models.CharField(max_length=50, blank=True)
status = models.BooleanField(default=False)
class User(models.Model):
username = models.CharField(max_length=50, blank=True)
password = models.CharField(max_length=50, blank=True)
contact_id = models.ForeignKey(Contact, on_delete=models.CASCADE, blank=True, null=True)
For these two models I have two serializer classes:
class ContactSerializerModel(serializers.ModelSerializer):
class Meta:
model = Contact
fields = ('name', 'status')
class UserSerializerModel(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password','contact_id')
I want to design a serializer class which takes name, username, password, and status fields. I want to post them as key-value pairs. First name and status value saved in the Contact model then with Contact model id saves username and password in User table. How to design the serializer class in Django rest API?
You need to override create method inside UserSerializerModel:
class UserSerializerModel(serializers.ModelSerializer):
contact_id = ContactSerializerModel()
class Meta:
model = User
fields = (
'username',
'password',
'contact_id'
)
def create(self, validated_data):
contact_data = validated_data.pop('contact_id')
contact = Contact.objects.create(**contact_data)
user = User.objects.create(contact_id=contact, **validated_data)
return user
See details here.
What you're looking for is writeable nested serializers, and there's a section of this in the DRF docs
I have a django app with which every registered user can create categories. For the authentication I am using django-all-auth. My models.py looks like this:
class Profile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
class Category(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
name = models.CharField(max_length=200, unique=True)
create_date = models.DateTimeField('date added', auto_now_add=True)
modify_date = models.DateTimeField('date modified', default=timezone.now)
On the index page the user can see the created categories and create new ones.
The views.py:
def CategoryView(request):
user = 0
if request.user.is_authenticated():
user = request.user
form = CategoryNameForm()
form.user = user
context = {
'categories': Category.objects.all(),
'form': form,
'user':user,
}
if request.method == 'POST':
form = CategoryNameForm(request.POST)
form.user = user
if form.is_valid():
form.save()
return render(request, 'myapp/index.html',context)
forms.py:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',)
The authentication works. So I was thinking to just put pass the user field into the form :
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name','user',)
hide it and then, just select it via JS since the user is in the context. I was just wondering if there is an easier way. This form.user = user for some reason didn't work, I get a NOT NULL constraint failure
There are couple of ways but here is one:
class CategoryNameForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name',) # take out user you don't need it here
def save(self, **kwargs):
user = kwargs.pop('user')
instance = super(CategoryNameForm, self).save(**kwargs)
instance.user = user
instance.save()
return instance
Then in view:
if form.is_valid():
form.save(user=request.user, commit=False)
Make sure your CategoryView is only accessible by authenticated user. Otherwise you will still get NOT NULL constraint failure for user.
I'm new to Django, and I've been fighting with this form for over a week now. I started this first because it is the core of my project. What I ultimately want is a single form that has a condition that the user can set, to add data to a second form when they check a radio box (will do that in jquery). I want to give admins the ability to register users, but I have a special subclass of users called operators that need additional information in a separate model. I almost have it working right now, but all users get added to the special subclass. Please help!
EDIT: What's not working is that I want to have the Admins register a user on a single form that can create users and if they check a button, then fill out the rest of the form for operators. I have the second part working (they can create an operator), but I also want them be able to create a regular user with the same form (that doesn't use the operator model). Can this be done?
Here is my code. NOTE: I messed up the password registration in this code, but I'll fix that later. Just working on this core functionality right now.
Models
class UserProfile(AbstractUser):
bio = models.TextField(max_length=500, blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_pic = models.ImageField(null=True, blank=True)
notes = models.TextField(null=True, blank=True)
def __str__(self):
return self.first_name + ' ' + self.last_name
class OperatorProfile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
cdl = models.ManyToManyField('CDL', blank=True)
endorsement = models.ManyToManyField('Endorsement', blank=True)
cdl_expiration = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.user)
Views
class OperatorCreateView(CreateView):
model = OperatorProfile
template_name = 'pages/operatorprofile_form.html'
form_class = UserCreationMultiForm
success_url = reverse_lazy('index')
def form_valid(self, form):
# Save the user first, because the profile needs a user before it
# can be saved.
user = form['user'].save()
user.groups.add(Group.objects.get(name='Operators'))
profile = form['profile'].save(commit=False)
profile.user = user
profile.save()
form['profile'].save_m2m()
return redirect(reverse_lazy('index'))
Forms
# Operator Creation Form
class OperatorProfileForm(forms.ModelForm):
class Meta:
model = OperatorProfile
exclude = ['user']
class UserProfileForm(forms.ModelForm):
first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
last_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
username = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))
password_confirm = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))
email = forms.CharField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
bio = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control'}))
def clean_password2(self):
password = self.cleaned_data.get('password1')
password_confirm = self.cleaned_data.get('password2')
if not password_confirm:
raise forms.ValidationError("You must confirm your password")
if password != password_confirm:
raise forms.ValidationError("Your passwords do not match")
return password_confirm
class Meta:
model = UserProfile
fields = ['username', 'password', 'password_confirm', 'first_name', 'last_name', 'bio']
class UserCreationMultiForm(MultiModelForm):
form_classes = {
'user': UserProfileForm,
'profile': OperatorProfileForm,
}