access django fk related objects in view as template - python

I have a models as
class Doctor(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=True,
related_name="user")
# other fields...
In my template, I easily can access the doctor object as request.user.doctor but using it in my views it causes the 'User' object has no attribute 'doctor' Error. so is it possible to access it as templates in my views too.

The related_name=… parameter [Django-doc] is the name of the relation in reverse, so to access the Doctor object from a User, since you have set this to user, you thus access the Doctor object with request.user.user, but that is misleading.
You thus better rename the relation to:
class Doctor(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=True,
related_name='doctor'
)
# other fields …
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related

How can I verify that all related fields in a Django REST Framework serializer specify objects with the same owner?

I have a Django app that uses django-organizations for supporting shared accounts, and rest_framework for an API. I have a custom model for authentication that relates the user to an API token specific to an organization.
I have a model with a few foreign keys, a serializer with related fields, and a ModelViewSet for the API views. I want to make sure that any API calls for creating or modifying instances of my model verify that the objects specified for the related fields have the same owner (organization).
class Bar(models.Model):
uuid = models.UUIDField(
default=uuid.uuid4, editable=False, unique=True)
organization = models.ForeignKey(
Organization, on_delete=models.CASCADE)
class Foo(models.Model):
uuid = models.UUIDField(
default=uuid.uuid4, editable=False, unique=True)
organization = models.ForeignKey(
Organization, on_delete=models.CASCADE)
bar = models.ForeignKey(
Bar, on_delete=models.CASCADE)
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ('uuid', 'organization', 'bar')
bar = serializers.SlugRelatedField(
slug_field='uuid', queryset=Bar.objects.all())
How can I verify that related objects belong to the same account? Ideally, I'd be able to override the queryset specified for each RelatedField in the serializer, but I don't think that's possible.
Two ways come to mind - you can do w/validation on the ModelSerializer, but you would have to then pass the request into a serializer. My gut says it probably makes more sense on the Viewset. That way, if it's accessing something that it shouldn't have access to it returns a 404 (less information leakage).
To have this on the viewset, define get_queryset w/
def get_queryset(self)
qs = MODEL.objects.filter(relation__user=self.request.user)
return qs
More examples below :
https://docs.djangoproject.com/en/2.1/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_queryset

Django ForeignKey create

I want to assign many Region to the UserProfile model, how to do it?
the code
class Region(models.Model):
name = models.CharField(max_length=30)
created_at = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(
region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True, blank=True)
The relation you describe is not a ForeignKey, which means that a UserProfile has (at most) one related Region, but a ManyToManyField [Django-doc].
A ManyToManyField thus means that a region can be related to zero, one, or more UserProfiles, and a UserProfile can be related to zero, one, or more Regions.
You can thus change the models to:
class Region(models.Model):
name = models.CharField(max_length=30)
created_at = models.DateTimeField(auto_now=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
regions = models.ManyToManyField(Region)
In a relational database this is implemented by adding an extra (hidden) table with ForeignKeys to Regions and UserProfiles. But the Django ORM works in a "transparant" way and thus hides the implementation details.
See the documentation for more information on how to "populate" such relation.
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
regions = models.ManyToManyField(Region,related_name='User')
I think this is the ideal way to implement what you need. Using ManyToManyField allows you to map userprofile object to more than one region object and vice versa.
Also, Inheriting Abstract User allows you to add region field to Django User Table, which is better than creating another table for linking user to and region field.

Issues with OneToOne Field in Serializer in django rest framework

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.

Defining the name of a ManyToOne relationship in Django

I would like to define a django model which has many-to-one relationship with itself. It is a user profile, connected as a OneToOne field with the authentication user model. I would like to save which user (if any) was the one who referred the 'current' user to my system. This means I have the following definition:
class UserProfile(models.Model):
user = models.OneToOneField(User, blank=True, related_name='profile')
class Meta:
abstract = True
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self')
I saw the django defaults to naming the set of referenced models by the name of the class with a suffix _set. I believe I will be getting something along the lines of specific_user_profile_set. I would much prefer to have it named u1.referrer and u2.referred or u2.referred_set. Is there any way this can be achieved?
related_name='profile'
This is the argument to define a name for any related field, so:
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self', related_name='referred')

Django Rest Framework not saving foreign key for a small number of requests

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.

Categories