I have model UserProfile related with User Model via one-to-one relationship.
UserProfileSerializer is defined correctly and it serializes userprofile object well.
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True)
country = models.CharField(max_length=255)
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('user','country')
But it gives error {'user':['This field is required']} on passing data.
>>> s = UserProfileSerializer(data = {'user':1,'country':'YY'} )
>>> s.is_valid()
False
>>> s.errrors
{'user':['This field is required']}
This might be too late to help, and I'm not sure exactly what you're trying to do, but try setting the user field in your serializer to use a PrimaryKeyRelatedField so that you can represent a User with an ID, or set the user field to be readonly if you only want to update UserProfile things. If you don't want to use a primary key, other relationship fields are here.
If you change the user field to be a PrimaryKeyRelatedField and you want the user data to return as it is now, you might want to make two UserProfile serializers - one for write operations, and one for reading. After a create or an update, you can switch to the read serializer to populate the response.
Related
So I have been searching all around the internet for a full example of how to user AbstractUser when u have at least 2 different models. Didn't find anything conclusive.. at least that would work on latest version of Django (2.0.1).
I have 2 models, teacher and student, and registration needs to be different. Besides username, email, name and surname, I need for example, for the student, to upload a profile picture, email, phone, student_ID. And for teacher, bio, academic title and website. Did I start good ? What is the right approach ?
class Profile(AbstractUser):
photo = models.ImageField(upload_to='students_images')
email = models.EmailField()
phone = models.CharField(max_length=15, )
class Student(Profile):
student_ID = models.CharField(unique=True, max_length=14,
validators=[RegexValidator(regex='^.{14}$',
message='The ID needs to be 14 characters long.')])
def __str__(self):
return self.name
class Teacher(Profile):
academic_title = models.CharField(max_length=30)
bio = models.TextField()
website = models.URLField(help_text="E.g.: https://www.example.com", blank=True)
Your goals can be accomplished using a 'Profile' pattern. You don't necessarily need to use a custom user model for this. But you need to have a single common model to for authentication; you can use the builtin django user for this or a custom class... Your Student and Teacher models should be OnetoOne relationships. This is the recommended solution per the documentation.
If you wish to store information related to User, you can use a OneToOneField to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user.
In your case, you may do something like this:
class StudentProfile(models.Model):
user = models.OneToOneField('User', related_name='student_profile')
# additional fields for students
class TeacherProfile(models.Model):
user = models.OneToOneField('User', related_name='teacher_profile')
# additional fields for teachers
Then you can create your registration forms based on these profile models.
class StudentResistrationForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = (...)
class TeacherRegistrationForm(forms.ModelForm):
class Meta:
model = TeacherProfile
fields = (...)
You can create the user instance to which the profile is related to at the same time you create the profile. You might do this with formsets, for example.
add
class Meta:
abstract = True
to profile model
and change AbstractUser to models.Model
I have the following situation: A user can have more than one profile. Here is my models class. Something like this example:
models.py:
class Profile:
name=models.Charfield()
class UserProfile:
user=models.ForeignKey(User)
profile = models.ForeignKey(Profile)
serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
Here I'm returning all my users by JSON but I would like to add a new field called profiles that returns all ids profiles that the user have.
{ "id": 1,
"name" : "John"
....
profiles = [1, 2]
}
How can I get(query) all profiles that the user have and add them on my final JSON?
on the UserSerializer declare the field profile as PrimaryKeyRelatedField
profiles = serializers.PrimaryKeyRelatedField()
By default this field is read-write, although you can change this behavior using the read_only flag.
see docs
1) Simplify relations - only User and Profile models needed in this case, you don't have to store explicit relation in UserProfile table as the same could be done in Profile model, as long as you don't need Users to share profiles with other Users.
2) Create ProfileSerializer
3) Add profiles field to UserSerializer with many=True property & provide reference in 'source' property
Please reffer to these docs as they are really good
http://www.django-rest-framework.org/api-guide/serializers/
Another thing to mention, creating UserProfile is depricated and in new versions of Django you can extend basic User model using setting property AUTH_USER_MODEL
In the tutorial, there's this loose one-to-one mapping between serializer fields and model fields. I can expect that if a serializer field and a model field are both CharFields it will save a string of characters when deserializing into a model instance:
models.py:
class Deck(models.Model):
created = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=100, unique=True, blank=False, null=False)
serializers.py:
class DeckSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Deck
fields = ('url', 'id', 'created', 'name')
extra_kwargs = {
'url': {
'view_name': 'goals:deck-detail',
}
}
But when I try a relationship, the serializer field is a ReadOnlyField, which from what I understand is essentially a Charfield, but the model field is a ForeignKeyField, and to add to the confusion, it seems like I'm saving an object in the views when I override perform_create:
models.py:
class Deck(models.Model):
created = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=100, unique=True, blank=False, null=False)
user = models.ForeignKey('users.User', related_name='decks', on_delete=models.CASCADE, null=False)
serializers.py:
class DeckSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
class Meta:
model = Deck
fields = ('url', 'id', 'created', 'name', 'user')
extra_kwargs = {
'url': {
'view_name': 'goals:deck-detail',
}
}
views.py:
class DeckList(generics.ListCreateAPIView):
serializer_class = DeckSerializer
def get_queryset(self):
return Deck.objects.all().filter(user__username=self.request.user)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
What's going on here? When dealing with relationships, why is it that I am saving an object by overriding perform_create in the views, declaring in the serializers a CharField, and in the models declaring a relationship field?
What's missing in my understanding, or what's really happening under the hood such that the user field (ForeignKey) can be represented as a string but saved as an object?
Edit:
If I'm overriding serializer.save(user=user) in the views and the serializers.py has the user field as
user = serializers.CharField(read_only=True)
And I want to override the save method in serializers.py, how do I pass the proper data so that it will know how to serialize? Do I just grab the whole User object, save it, and it'll do the rest? Is the serializers.save() override in the views the same as serializers.save() in serializers.py?
Not 100% sure that I've understood what you're asking, but if the question is:
What's happening under the hood when a ForeignKey field is saved in the Django ORM?
Then the answer is that:
The relation is saved in the DB as an (e.g.) int field which stores the primary key of the related object.
The ForeignKey field reference section in the Django docs explains how this part of the ORM works, and the "Database Representation" subsection likely touches on the specific bit you're interested in.
For example, for your case of User being a related field in the Deck model the underlying table would likely look like this (assuming postgresql):
myapp_deck
id int
created timestamp
name varChar
user_id int
The Deck -> User relation is mapped by the DB storing the pk for the related User object in the user_id field in the myapp_deck table.
So, all Django (and, consequently, DRF) needs to do to change the User in the Deck model is change the user_id in the myapp_deck table to the PK of a different User object.
Hope this helps, and please let me know if I've missed the point of your question.
Edited to Add Example of Custom .create() method
If you want to override the custom "save" method in a serializer then the methods to override are create() and update() accordingly (see Serializer "Saving instances" section in the DRF docs).
An example of this might be:
class DeckSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
... Rest of your serializer code ...
def create(self, validated_data, **kwargs):
user_obj = User.objects.get(pk=validated_data["user"])
deck = Deck.objects.create(
name=validated_data["name"],
user=user_obj,
)
return deck
Note: This assumes that the pk of the related User object is passed throught the serializer, validates OK, and is available in the validated_data dict.
I use the default User class from from django.contrib.auth.models import User. In the user creation when the user is created I set the username field to a random hash. When I use the model in ManyToMany field and use it in the Django admin then the random hash is rendered in the select box. Is there a way to specify the field to be taken from the model to be displayed in the select box so that I can specify the model as ManyToMany field and use the email to be rendered in the django admin form.
class TestModel(models.Model):
group = models.ManyToManyField(Group, null=True)
user = models.ManyToManyField(User, null=True)
Is there a field like the display_name that can be passed to the model field so that the appropriate field can be taken from the ManyToMany model for rendering. I am using Django 1.5.5
I think you need to do something like this,
class TestModelAdminForm(forms.ModelForm):
user = forms.MultipleChoiceField(choices=[ (user.id, user.email) for user in User.objects.all()])
class Meta:
model = TestModel
fields = ('user','group')
class TestModelAdmin(admin.ModelAdmin):
form = TestModelAdminForm
I am using Django Rest Framework to provide API to a mobile app. I have two models, Order and User. Order has a foreign key relation to User.
For about 1% or so of all my order objects, the User field is null. I've been testing this behavior using cURL.
If I do a cURL without a user object, it tells me "This field is required".
If done with a wrong user object, it tells me that the object does not exist. Both of these are the intended and expected behaviors.
I'm trying to figure out how it is possible for some of the Order objects to be saved without a user field. Is there something I'm not taking into account?
My views:
class OrderList (generics.ListCreateAPIView):
model = Order
serializer_class = OrderSerializer
And serializer:
class OrderSerializer (serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field = 'user')
partial = True
class Meta:
model = Order
Models:
class User (models.Model):
uid = models.CharField(max_length =200, unique=True)
class Order (models.Model):
uid = models.ForeignKey (User, related_name = "orders", verbose_name = "User",blank=True, null=True)
You could use two different ModelSerializer classes, one for creation, that makes sure, that an Order object can't be created without a related User and one for updating orders, that passes required=False to the related field's constructor, so that you still can save existing orders that haven't a related User.
Try adding default=None to your models.ForeignKey declaration. You could also just create an anonymous user in the users table and when the user isn't specified it could set the anonymous user instead.