I have a model, configuration, in Django and wish to fill the author field with get_username
Can this be done within the model or must it be done from the form? If it must be on the form, how can I change the standard admin page to have this functionality?
At present, the model reads thus:
class Configuration(models.Model):
title = models.CharField(max_length=100,unique=True,blank=False)
author = models.CharField(max_length=50,blank=False)
created = models.DateTimeField("date created",auto_now_add=True)
modified = models.DateTimeField("date modified",auto_now=True)
description = models.CharField(max_length=512)
drawing = models.ForeignKey(Drawing)
instruments = models.ManyToManyField(Instrument)
def __unicode__(self):
return self.title
Use models.ForeignKey:
#models.py
from django.contrib.auth.models import User
class Configuration(models.Model):
author = models.ForeignKey(User)
...
#admin.py:
class Configuration_admin(admin.ModelAdmin):
fields = ('title', 'author',....)
something like that:
from django.contrib.auth.models import User
class ...
...
username = models.ForeignKey(User)
If you want to make some relationship between your model and default User model then you can extends the User model into your own custom model , like this:
models.py
from django.contrib.auth.models import User
class Configuration(models.Model):
author = models.OneToOneField(User)
..
..
Related
Hello I had to rewrite my user model for add some filed, I used AbstractUser
My models:
It's on blog app:
class Article(models.Model):
author = models.ForeignKey(User , null=True, on_delete=models.SET_NULL , related_name='articles' , verbose_name='نویسنده')...
it's on account app:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
is_authour = models.BooleanField(default=False, verbose_name="وضعیت نویسندگی")
special_user = models.DateTimeField(default=timezone.now, verbose_name="کاربر ویژه تا")
def is_special_user(self):
if self.special_user > timezone.now():
return True
else:
return False
is_special_user.boolean = True
is_special_user.short_description = "وضغیت کاربر ویژه"
I imported my User view in this way:
from account.models import User
And I added this to my setting:
AUTH_USER_MODEL = 'account.User'
when I migrate I get this error:
blog.Article.author: (fields.E301) Field defines a relation with the
model 'auth.User', which has been swapped out.
HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
I searched my error but I can't find my solution
The current User passed to the ForeignKey points to the auth.User right now, not your custom User.
As the HINT itself suggests, use settings.AUTH_USER_MODEL instead of User in your author field in Article model.
class Article(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL, related_name='articles', verbose_name='نویسنده')...
Link to django docs: Using a custom user model
Did you register the model in the app's admin.py?
Furthermore, changing the user model mid-project...this can be a hassle, look here: Changing to a custom user model mid-project
I think you are importing User model from django auth app.
Change the author field in the Article model as follows:
class Article(models.Model):
author = models.ForeignKey('account.User', null=True, on_delete=models.SET_NULL, related_name='articles', verbose_name='نویسنده')
...
So basically I have a django model that has a ManyToManyField of friends and two methods that run on it. Here are my files:
Models.py:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
friends = models.ManyToManyField(User, blank=True, related_name='friends')
def friends_list(self):
return self.friends.all()
def number_of_friends(self):
return self.friends.all().count()
Serialzers.py:
from rest_framework import serializers
from .models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
Views.py:
from rest_framework import viewsets, permissions
from .models import Profile
from .serializers import ProfileSerializer
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = ProfileSerializer
The issue is that in the Api, the return values of the method aren't there. The friends_list method for example is supposed to return a list of friends you have and even though this does work in a traditional django project, the Django Rest Framework is not showing any value for this method. How can I fix this and get the return values for both methods to show up in the api?
Since the model serializer picks up only model fields for the serializer fields, you won't automatically get any methods copied over.
You can still send this read only data over the API by explicitly adding the two fields with reference to the model methods
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = [
# need to explicitly define all fields I believe
'friends_list',
'number_of_friends',
]
Now that the two fields (matching the method name are declared, DRF should create SerializerMethodField or ReadOnly field (not sure which one, but they are similar) for each of them.
It works coz it sets the source for those fields to be the same name, and if finds some attribute (in this case the methods) on the model.
If that doesn't work, you can
class ProfileSerializer(serializers.ModelSerializer):
friends_list = serializers.SerializerMethodField()
number_of_friends = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = [
# need to explicitly define all fields I believe
'friends_list',
'number_of_friends',
]
def get_friends_list(self, instance):
return instance.friends_list()
def get_number_of_friends(self, instance):
return instance.number_of_friends()
when you use __all__ it call fields only you have to call fields with methods using list like that
`fileds = ["first_name","last_name","user",
"friends","friends_list","number_of_friends"
]`
I'm kinda new to django, I need to set a dynamic initial value to my modelform field. I have a database field in my model name 'author' it has a foreignkey that connects it to the django user model. I need to automatically set this to the current user anytime a user fills in information into the form.
from what I gathered about this problem, I'd have to define an __init__ function inside the MyHouseEditForm below, I'm new to django and all the examples I've seen a pretty confusing.
forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Myhouses
class MyHouseEditForm(forms.ModelForm):
class Meta:
model = Myhouses
fields = ('author','name_of_accomodation', 'type_of_room', 'house_rent', 'availability', 'location', 'nearest_institution', 'description', 'image')
i need to set the value of 'author' to the current user anytime a user logs in.
models.py
from django.db import models
from django.contrib.auth.models import User
class Myhouses(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
name_of_accomodation = models.CharField(max_length=200)
type_of_room = models.CharField(max_length=200)
house_rent = models.IntegerField(null=True)
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='profile_image')
def __str__(self):
return self.name_of_accomodation
views.py
#login_required
def addlisting(request):
if request.method == 'POST':
form = MyHouseEditForm(request.POST, files=request.FILES)
if form.is_valid():
Houses = form.save(commit=False)
Houses.save()
return redirect('addlisting')
else:
form = MyHouseEditForm()
return render(request, 'houses/addlisting.html', {'form':form })
No need to show author field in form. It would automatically populate with logged in user.
request.user gives you logged in user object. So, you may remove 'author' filed from forms field section and do this:
Houses = form.save(commit=False)
Houses.author = request.user
Houses.save()
I did something like this in the serializer.
I defined a custom create method like this:
class MyhousesSerializer(FlexFieldsModelSerializer):
...
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
newhouse = Myhouses.objects.create(**validated_data)
return newhouse
It shouldn't matter if you use a more regular model serializer.
I'm trying to link 'owner' field of my model to an AbstractUser. I need it to be done automatically, the only think i'm able to do by myself is to allow user logged in to choice between every existing user with, what's not what i want. I would like to not have a field to manipulate, but a outcome serializer with id or username of User that added the model. I'm trying to find solutions for a few days, I've tried already combine ForeignKey, PrimaryKeys, OneToOneField, HiddenField, get_user, perform_create, but I'm for sure doing something wrong, and i'm almost lost with it. The last thing i tried is to def_perform in views like DRF QuickStart tutorial say, but without results.
I add some code sample to be more understandable:
There is my AbstractUser model:
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
username = models.CharField(max_length=20, unique=True)
...
i added it to AUTH_USER_MODEL = in the settings.
And there is other model which i want to link with User:
from django.db import models
from users.models.user import UserProfile
class MyPhoto(models.Model):
owner = models.ForeignKey(UserProfile, related_name='photos', on_delete=models.CASCADE, null=True)
image = models.ImageField(upload_to='Images')
serializer.py
class MyPhotoSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = MyPhoto
fields = ('pk', 'image', 'owner')
def create(self, validated_data):
photo = MyPhoto.objects.create(
image=validated_data['image']
)
photo.save()
return photo
views.py
class UpdateMyPhotoViewSet(viewsets.ModelViewSet):
queryset = MyPhoto.objects.all()
serializer_class = MyPhotoSerializer
permission_classes = (IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
and for now i can't see the owner field results.
Thanks in advance.
I am having some trouble in selecting data in Django.
models.py
class Location(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
my_location = models.CharField(max_length=120, choices=LOCATION_CHOICES)
update_date = models.DateField(auto_now=True, null=True)
date = models.DateField()
def __str__(self):
return self.my_location
class UserProfile(models.Model):
user = models.ForeignKey(User)
user_base = models.CharField(max_length=120, choices=LOCATION_CHOICES)
user_position = models.CharField(max_length=120)
user_phone = models.PositiveIntegerField()
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.user)
super(UserProfile, self).save(*args, **kwargs)
def __unicode__(self):
return self.user.username
views.py
def index(request):
locations = Location.objects.order_by('-update_date')
context = {'locations': locations}
return render(request, 'index.html', context)
I was able to show the email from User module but what I really want to show is the data from UserProfile.
Please, any advice.
Thank you.
Instead of using
user = models.ForeignKey(User)
use:
user = models.OneToOneField(User)
One-to-one relationships suit better your case. If you use them, your User model will automatically get a userprofile attribute that you can use like this:
>>> user = User.objects.get(...)
>>> user.userprofile.user_phone
12345
You can also consider writing a custom User model, so that you can get rid of UserProfile.
Bonus tip: PositiveIntegerField is not the right field for a phone number. Leading zeroes have a meaning. Also, PositiveIntegerField have a maximum value. Use CharField instead.
Use a OneToOneField
To make it more direct, I'd make the UserProfile have a OneToOneField relationship with User, instead of a ForeignKey. Because this will mean that a given user can only have one profile.
class Location(models.Model):
user = models.OneToOneField(User)
In which case you can access it easier with location.user.userprofile.your_field
Using a custom MyUser model
If you want to make this even more direct, you could make a custom MyUser model that will contain both the fields from User and UserProfile.
It would go roughly like this:
from django.contrib.auth.models import AbstractBaseUser
class MyUser(AbstractBaseUser):
# Adding your custom fields
user_base = models.CharField(max_length=120, choices=LOCATION_CHOICES)
user_position = models.CharField(max_length=120)
user_phone = models.CharField(max_length=120)
slug = models.SlugField()
class Location(models.Model)
user = OneToOneField(MyUser) # Using your custom MyUser model
This allows a more direct access, e.g. location.user.user_phone instead of location.user.userprofile.user_phone
I've only provided pseudocode, please refer to Django documentation
Using a ForeignKey means you may have multiple profiles
In the other case where a user may have multiple user profiles, you then have the burden on you to select which profile to use to pull the relevant data from, because then the relationship would be user.userprofile_set, a set that you will have to filter/index to choose from.