How to pre-fill a Django model - django

Like :
class Article (models.Model):
user = models.ForeignKey('User', related_name="articles")
def __init___(self):
self.user = 'Friendy'

Presuming you mean to add a default value to the user field, there are two ways: either a simple value based default, or you can use a callable as the default. The documentation for this can be found at https://docs.djangoproject.com/en/2.2/ref/models/fields/#default
If you want to default to specific user, then you would need to know the id of the user, like so:
class Article (models.Model):
user = models.ForeignKey(
'User',
related_name="articles",
default=1,
help_text="There better be a user with an id of 1 or this will not work",
)
def __init___(self):
self.user = 'Friendy'
The other way is to define a callable that returns the id of the user, like so:
def get_first_user():
user = User.objects.first()
if user:
return user.pk
return None
class Article (models.Model):
user = models.ForeignKey(
'User',
related_name="articles",
default=get_first_user,
help_text="There better be a user with an id of 1 or this will not work",
)
def __init___(self):
self.user = 'Friendy'
The reason we return the id and not the User instance is because of this line in the docs:
For fields like ForeignKey that map to model instances, defaults should be the value of the field they reference (pk unless to_field is set) instead of model instances.

Related

Django annotate with other model attributes based on a common field

I have a User model,
class User(AbstractBaseUser):
id = models.IntegerField(primary_key=True)
email = models.EmailField(unique=True)
I have another model named Company. The Company model has a reference to User model via an Integer field.
class Company(models.Model):
user_id = models.IntegerField(db_index=True)
name = models.CharField(max_length=100)
size = models.IntegerField(default=1)
I wanted to extract the company information along with user information.
basically I want a user object dictionary like this {'id':1, 'email':'abc#gmail.com','name':'foobar.co','size':400}
I want to annotate the user objects with name and size. As of now, I tried in the serializer's to_representation method. However, for millions of users this is super slow.
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField(read_only=True)
def to_representation(self, instance):
response = super(UserSerializer, self).to_representation(instance)
company = Company.objects.filter(user_id=instance.id)
if company.exists():
company = company.first()
response['name'] = company.name
response['size'] = company.size
return response
How can I achieve this annotation in the query itself.
If the links in the comment do not help you, You can use SerializerMethodField for name, and size
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField(read_only=True)
name = serializers.SerializerMethodField()
size = serializers.SerializerMethodField()
def get_name(self, obj):
# get name from DB using the User object(obj)
return name
def get_size(self, obj):
# get size from DB using the User object(obj)
return size

How to create two users : Buyers/Sellers in Django

I'm working on a project on how to create Two users : buyers/Sellers for Web using Django as Backend.
I've started the app "users"
I've read the Django Documentation about CustomUserModel
But Honestly don't know where to start from.
Any Suggestions?
In my opinion, a Buyer might be a seller and a seller might be a Buyer.
There are some suggestions:
Create your own application named users (This will help you full control User object in future).
Set your AUTH_USER_MODEL settings to users.User: AUTH_USER_MODEL = 'users.User' As you defined.
Define model Seller - OneToOne -> User: This contains seller's properties, Just create when access via user.seller
Define model Buyer - OneToOne -> User: This contains buyer's properties, just create when access via user.buyer
class User(AbstractUser):
# Your user's properties
# Your user's method
#property
def buyer(self):
try:
return Buyer.objects.get(user=self)
except Buyer.DoesNotExist:
default_value_of_buyer = {}
# Or define default value at model fields
return Buyer.objects.create(user=self, **default_value_of_buyer)
#property
def seller(self):
try:
return Seller.objects.get(user=self)
except Seller.DoesNotExist:
default_value_of_seller = {}
# Or define default value at model fields
return Seller.objects.create(user=self, **default_value_of_seller)
class Buyer(models.Model):
"""
You can add this to admin page to make some actions with Buyer
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, related_name='buyer_profile')
# Other properties of Buyer
def __str__(self):
return "%s's Buyer profile" % self.user
class Seller(models.Model):
"""
You can add this to admin page to make some actions with Seller
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, on_delete=models.CASCADE, related_name='seller_profile')
# Other properties of Seller
def __str__(self):
return "%s's Seller profile" % self.user
It is not that hard buddy look:
you create a model User
class User(models.Model):
.........
types = (('b','buyer'),('s','seller'))
user_type = models.CharField(max_length=7, choices=types)
so every field has this argument called choices, it is a tuple that has tuples in it, every sub tuple is a choice and every choice has two elements the first one is what appears in the back end and the second element is what appears in the user interface, so 'b' is what appears in the back end and 'buyer' is what the user see in the form in the web site. Tell if that didn't work for you
class Account(models.Model):
types = (
('B', 'BUYER' ),('S', 'SELLER')
)
name = models.Charfield(max_length=15)
username = models.CharField(max_length=15)
email = models.EmailField()
password = models.CharField(max_length=16)
user_type = models.CharField(max_length=12, choices=types)
TRY THIS AND THEN GO TO YOUR ADMIN PAGE AND YOU WILL UNDERSTAND EVERYTHING

How to create model objects that belong to unique user

I am setting up a delivery app .I want to be able to create a Reciever that belongs to the user logged in when created.
class CustomUser(AbstractUser):
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
email = models.EmailField(blank=False)
class Reciever (models.Model):
name = models.CharField(max_length=256,blank=False)
I want to create a Reciever object that belongs to a particular user.
When i create a Reciever now , it is available to all users.
In that case you can use a OneToOneField [Django-doc], which is a ForeignKey [Django-doc], but with a uniqueness constraint attached to it, like:
class Reciever(models.Model):
name = models.CharField(max_length=256,blank=False)
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
In the view, you can thus attach the logged in user to the Receiver, like:
def some_view(request):
Receiver.objects.create(name='foo', user=request.user)
given of course you already made CustomUser your customer model [Django-doc].
If you made a ModelForm, you can exclude the user field, and set it in the view, for example:
def some_view(request):
form = ReceiverForm(request.POST)
if form.is_valid():
object = form.save(commit=False)
object.user = request.user
object.save()
# ...
# ...

Initial value for dropdown menu

I'd like to set an initial value on my dropdown form of "Select an Industry". Once the user selects a valid value from the dropdown AND saves the form, ideally, this option wouldn't be visible anymore within the list if the user were to go back to the form. If there is no way to do this, that's fine.
Models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(blank=True, null=True, max_length=100)
industry = models.IntegerField(default=0)
Forms.py
class EditUserProfileForm (forms.ModelForm):
industry = forms.ChoiceField()
def __init__(self, *args, **kwargs):
super(EditUserProfileForm, self).__init__(*args, **kwargs)
self.fields['industry'].choices = [(t.industry, t.industryname) for t in Industry.objects.all()]
class Meta:
model = UserProfile
fields = (
'phone',
'industry',
)
Is it possible to set a default value without creating an instance of the Industry object whose industryname is "Select and Industry"?
Thanks!
If industry is an integer representing entries in a separate table, then it is a foreign key. Make it an actual ForeignKey field; then Django will automatically output a select box for that related model in your form.

Django rest framework : extend user model for customer - one to one field

I have a customer model in Bcustomer app that extends the django User model, So I will save the basic details such as name in User table and the remaining data (city, etc) in customer table.
When I call the below code through API, it shows the following error. But data is saving in the tables. I also want to implement the get and put calls for this api.
Got AttributeError when attempting to get a value for field `city` on serializer `CustomerSerializer`.
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 'city'.
my Bcustomer/models.py
class BCustomer(models.Model):
customer = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True, blank=True )
address = models.CharField(max_length=50)
city = models.CharField(max_length=256)
state = models.CharField(max_length=50)
user = models.ForeignKey(settings.AUTH_USER_MODEL, db_index=True, on_delete=models.CASCADE, related_name='customer_creator')
# more fields to go
def __str__(self):
# return str(self.name) (This should print first and last name in User model)
class Meta:
app_label = 'bcustomer'
my Bcustomer/serializers.py
from django.contrib.auth import get_user_model
from models import BCustomer
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
city = serializers.CharField()
class Meta:
model = get_user_model()
fields = ('first_name', 'email','city')
def create(self, validated_data):
userModel = get_user_model()
email = validated_data.pop('email', None)
first_name = validated_data.pop('first_name', None)
city = validated_data.pop('city', None)
request = self.context.get('request')
creator = request.user
user = userModel.objects.create(
first_name=first_name,
email=email,
# etc ...
)
customer = BCustomer.objects.create(
customer=user,
city=city,
user=creator
# etc ...
)
return user
my Bcustomer/views.py
class CustomerViewSet(viewsets.ModelViewSet):
customer_photo_thumb = BCustomer.get_thumbnail_url
permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]
queryset = BCustomer.objects.all()
serializer_class = CustomerSerializer
my Bcustomer/urls.py
router.register(r'customer', views.CustomerViewSet, 'customers')
POST request format
{
"first_name":"Jsanefvf dss",
"city":"My City",
"email":"myemail#gmail.com",
#more fields
}
I also need to implement put and get for this api. Now data is saving in both tables but shows the error.
Sure it complains.
Validation goes well, so does the creation but once it's created, the view will deserialize the result and return it to the client.
This is the point where it goes south. Serializer is configured to think that city is a field of the default user while it actually is part of BCustomer. In order to work this around, you should set the source argument to the city field. You might need to update the serializer's create/update to reflect that change, not sure about that one.