I'm trying to save the last IP of User to the Profile module in Django but I get always NOT NULL constraint failed I know that last_ip should be set tonull=True and I run this commands:py .\manage.py makemigrations and py .\manage.py migrate. if you have any suggestions to save IP to the user that will be helpful for me.
Thanks in advance.
#models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True, max_length=150)
last_ip = models.GenericIPAddressField(null=True, blank=True)
avatar = ContentTypeRestrictedFileField(max_upload_size=10485760, null=True, verbose_name="",default='default.jpg', blank= True, content_types=['image/png', 'image/jpeg'])
def __str__(self):
return self.user.username
#forms.py
class UpdateUserForm(forms.ModelForm):
username = forms.CharField(max_length=150, required=True)
first_name = forms.CharField(max_length=150, required=False)
last_name = forms.CharField(max_length=150, required=False)
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ['username','first_name','last_name','email']
class UpdateAvatarBio(forms.ModelForm):
avatar = forms.ImageField()
bio = forms.CharField()
class Meta:
model = Profile
fields = ['avatar', 'last_ip', 'bio']
#views.py
def ip_client(request):
return (
x_forwarded_for.split(',')[0]
if (x_forwarded_for := request.META.get('HTTP_X_FORWARDED_FOR'))
else request.META.get('REMOTE_ADDR')
)
def profile(request):
ip = ip_client(request)
model = Profile(last_ip=ip)
model.save() # Traceback suppose here is the issue
if request.method == 'POST':
...
...
return render(request, 'profile.html', {'user_form': user_form, 'profile_form': profile_form})
You didn't add the user to Profile before saving it
def profile(request):
ip = ip_client(request)
model = Profile(last_ip=ip)
moddl.user=request.user #Add this
model.save() # Traceback suppose here is the issue
if request.method == 'POST':
...
...
return render(request, 'profile.html', {'user_form': user_form, 'profile_form': profile_form})
Edit:
Since the user is OneToOne (which means it is a the primary key), so Your code shall be like this
def profile(request):
ip = ip_client(request)
profile = Profile.objects.get(user=request.user)
profile.last_ip = ip
profile.save()
if request.method == 'POST':
...
...
return render(request, 'profile.html', {'user_form': user_form, 'profile_form': profile_form})
Related
I am working on an app and need help I want to authenticate LinkedIn and save the access token in a table and then collect the LinkedIn user details in another table below is my model.py
class LinkedInUserCode(models.Model):
"""
Credentials for the user to give access to LinkedIn.
"""
user = models.OneToOneField(User, on_delete=models.CASCADE)
token = models.CharField(max_length=1024)
expires_in = models.IntegerField()
def __str__(self):
return f'{self.token}'
class Meta:
db_table = 'linkedin_user_code'
verbose_name_plural = "LinkedIn User Codes"
class LinkedInProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
linkedin_id = models.CharField(max_length=1024, blank=True, null=True)
first_name = models.CharField(max_length=1024, blank=True, null=True)
last_name = models.CharField(max_length=1024, blank=True, null=True)
profile_image_url = models.CharField(max_length=1024, blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return f'{self.linkedin_id}'
class Meta:
db_table = 'linkedin_profile'
verbose_name_plural = "LinkedIn Profiles"
I am using a nested serializer and this is my serialiser
class LinkedInProfileSerializer(ModelSerializer):
"""
Serializer for the LinkedInProfile model.
"""
id = IntegerField(required=False)
user = ReadOnlyField(source='user.email')
linkedin_access = ReadOnlyField(source='linkedin_access.token')
class Meta:
model = LinkedInProfile
fields = '__all__'
def create(self, validated_data):
"""
Create a new LinkedInProfile instance.
"""
return LinkedInProfile.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.linkedin_id = validated_data.get('linkedin_id')
instance.first_name = validated_data.get('first_name')
instance.last_name = validated_data.get('last_name')
instance.profile_image_url = validated_data.get('profile_image_url')
instance.linkedin_access = validated_data.get('linkedin_access')
instance.save()
return instance
class LinkedInUserCodeSerializer(ModelSerializer):
user = ReadOnlyField(source='user.email')
profiles = LinkedInProfileSerializer(many=True, read_only=True)
class Meta:
model = LinkedInUserCode
fields = ['user', 'token', 'expires_in', 'profiles']
def create(self, validated_data):
""" Create and return necessary credentials for linkedin."""
profile = validated_data.pop('profiles')
access_token = LinkedInUserCode.objects.create(**validated_data)
for profile_data in profile:
LinkedInProfile.objects.create(linkedin_access=access_token, **profile_data)
return access_token
def update(self, instance, validated_data):
profiles = validated_data.pop('profiles')
instance.token = validated_data.get('token', instance.token)
instance.expires_in = validated_data.get('expires_in', instance.expires_in)
instance.save()
temp_profile = []
existing_ids = [profiles.get('linkedin_id') for profile in instance.profiles.all()]
for profile_data in profile:
if profile_data.get('linkedin_id') in existing_ids:
temp_profile.append(LinkedInProfile.objects.get(linkedin_id=profile_data.get('linkedin_id')))
else:
temp_profile.append(LinkedInProfile.objects.create(linkedin_access=instance, **profile_data))
instance.profiles.set(temp_profile)
for profile in instance.profiles.all():
if profile not in temp_profile:
profile.delete()
return instance
I have written a script that I am using to make requests to the LinkedIn api and here is my view I want to populate it at once any idea how I can go about it I keep having issues with the foreign key of LinkedIn_access
class LinkedInCallbackAPIView(APIView):
"""
This View is used to get and save the Access Token from LinkedIn authorization page.
"""
def get(self, request, *args, **kwargs):
response = request.GET
if response is not None and state != response.get('state'):
return Response({'error': "Invalid state"}, status=status.HTTP_401_UNAUTHORIZED)
else:
queryset = LinkedInUserCode.objects.filter(user=request.user)
code = response.get('code')
access_token = linkedin.get_access_token(code)
profile = linkedin.get_user_profile(access_token.get('access_token'))
profile = {
'linkedin_id': profile.get('id'),
'first_name': profile.get('firstName').get('localized').get('en_US'),
'last_name': profile.get('lastName').get('localized').get('en_US'),
'profile_image_url': profile.get('profilePicture').get('displayImage'),
}
data = {
'token': access_token.get('access_token'),
'expires_in': access_token.get('expires_in'),
'user': request.user,
'profiles': profile,
}
serializer = LinkedInUserCodeSerializer(data=data)
if queryset.exists():
serializer.update(queryset.first(), data)
return Response({'message': 'Your LinkedIn user Access Token was Updated'},status=status.HTTP_200_OK)
if serializer.is_valid():
serializer.save(**data)
# there will be a return response here
I need help passing this table and not using a single table for it
thank you
Followed the tutorial on creating meetups and allow participants join them. When adding a participant (his email address) using the form, the email address is added to all meetings, not just the one he joined. I am new to Django, but it seems like the problem is in the ManyToMany relationship.
Models.py
from django.db import models
class Location(models.Model):
name = models.CharField(max_length=200)
address = models.CharField(max_length=300)
def __str__(self):
return f'{self.name} ({self.address})'
class Participant(models.Model):
email = models.EmailField(unique=True)
def __str__(self):
return self.email
class Meetup(models.Model):
title = models.CharField(max_length=200)
organizer_email = models.EmailField()
date = models.DateField()
slug = models.SlugField(unique=True)
description = models.TextField()
image = models.ImageField(upload_to='images')
location = models.ForeignKey(Location, on_delete=models.CASCADE)
participants = models.ManyToManyField(Participant, blank=True)
def __str__(self):
return f'{self.title} - {self.slug}'
Views.py
from django.shortcuts import render, redirect
from .models import Meetup, Participant
from .forms import RegistrationForm
# Create your views here.
def index(request):
meetups = Meetup.objects.all()
return render(request, 'meetups/index.html', {
'meetups': meetups
})
def meetup_details(request, meetup_slug):
try:
selected_meetup = Meetup.objects.get(slug=meetup_slug)
if request.method == 'GET':
registration_form = RegistrationForm()
else:
registration_form = RegistrationForm(request.POST)
if registration_form.is_valid():
user_email = registration_form.cleaned_data['email']
participant, _ = Participant.objects.get_or_create(email=user_email)
selected_meetup.participants.add(participant)
return redirect('confirm-registration', meetup_slug=meetup_slug)
return render(request, 'meetups/meetup-details.html', {
'meetup_found': True,
'meetup': selected_meetup,
'form': registration_form
})
except Exception as exc:
return render(request, 'meetups/meetup-details.html', {
'meetup_found': False
})
def confirm_registration(request, meetup_slug):
meetup = Meetup.objects.get(slug=meetup_slug)
return render(request, 'meetups/registration-success.html', {
'organizer_email': meetup.organizer_email
})
Forms.py
from django import forms
class RegistrationForm(forms.Form):
email = forms.EmailField(label='Your email')
If somebody has this kind of issue, answer is below, did it :)
I have two apps (accounts and company).
accounts/models.py
class Organization(models.Model):
organization_name = models.CharField(max_length=20)
#custom user model
class NewUser(AbstractBaseUser):
which_organization = models.ForeignKey(Organization, on_delete = models.CASCADE, null=True, blank=True)
#other fields
company/models.py
from accounts import models as accounts_model
class Branch(models.Model):
branch_name = models.ForeignKey(
accounts_model.Organization, on_delete = models.CASCADE, null=True, blank=True)
#other fields
company/forms.py
from .models import Branch
class BranchForm(forms.ModelForm):
class Meta:
model = Branch
fields = '__all__'
company/views.py
from .forms import BranchForm
def some_function(request):
form = BranchForm()
if request.method == 'POST':
form = BranchForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=False)
form.branch_name = request.user.which_organization
print("User organization: ", request.user.which_organization)
form.save()
return render(request, 'company/index.html', {'form': form})
P.s. Everything works well. I am able to print the user's organization with
print("User organization : ", request.user.which_organization)
But cannot save it with
form.branch_name = request.user.which_organization
in views.py. Instead of getting exact organization name of the user, created object lists all organization names...
How to achieve it?)
Did it :D
def some_function(request):
form = BranchForm()
if request.method == 'POST':
form = BranchForm(request.POST, request.FILES)
if form.is_valid():
another_form = form.save(commit=False)
another_form.branch_name = Organisation.objects.get(id= request.user.which_organization.id )
new_form.save()
return render(request, 'company/index.html', {'form': form})
Try passing an instance of the Organisation model,
def some_function(request):
form = BranchForm()
if request.method == 'POST':
form = BranchForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=False)
organisation_instance = Organisation.objects.get(id = request.user.which_organization.id )
form.branch_name = organisation_instance
print("User organization: ", request.user.which_organization)
form.save()
return render(request, 'company/index.html', {'form': form})
I have three models that are related to each other, namely:
models.py
class Shop(models.Model):
number = models.PositiveSmallIntegerField()
name = models.CharField(db_index=True)
city = models.ForeignKey(ShopCity, on_delete=models.CASCADE)
class Product(models.Model):
name = models.CharField(db_index=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
class ProductQuantity(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
shop = models.ForeignKey(Shop, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(default=None)
In the admin panel they are linked in this way:
admin.py
class ProductQuantityInline(admin.TabularInline):
model = ProductQuantity
extra = 0
#admin.register(Product)
class ProductAdmin(ImportExportActionModelAdmin):
fields = ['name', 'price']
list_display = ['name', 'price']
inlines = [ProductQuantityInline]
There is a need to overwrite data with REST API
serializers.py
class QuantitySerializer(serializers.ModelSerializer):
class Meta:
model = ProductQuantity
fields = ('shop', 'quantity')
class ProductSerializer(serializers.ModelSerializer):
productquantity = serializers.SerializerMethodField(read_only=False)
class Meta:
model = Product
fields = ('name', 'price', 'productquantity')
def get_productquantity(self, obj):
return [QuantitySerializer(s).data for s in obj.productquantity_set.all()]
And finally my handler for REST API:
views.py
#api_view(['GET', 'PATCH', 'PUT', 'DELETE'])
def api_product_detail(request, pk):
product = Product.objects.get(pk=pk)
if request.method == 'GET':
serializer = ProductSerializer(product)
return Response(serializer.data)
elif request.method == 'PUT' or request.method == 'PATCH':
serializer = ProductSerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
As a result, data such as the name and price are overwritten, and the productquantity is not overwritten.
What am I doing wrong? Thanks for any help.
I currently use a function based view to let users write comments on posts, but I'm trying to convert it to class based views
Function views.py
def comment(request, pk):
form = CommentForm(request.POST)
# Post instance
post_instance = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
if form.is_valid:
obj = form.save(commit=False)
obj.commenter = request.user
obj.post = post_instance
obj.save()
return redirect('/')
else:
messages.error(request, 'Comment Failed')
return render(request, 'comment.html', {'form': form})
Class views.py
class CommentView(FormView):
template_name = 'comment.html'
form_class = CommentForm
success_url = '/'
def get_object(self):
pk = self.kwargs.get('pk')
post_instance = get_object_or_404(Post, pk=pk)
return post_instance
def form_valid(self, form):
obj = form.save(commit=False)
obj.commenter = self.request.user
obj.post = post_instance
obj.save()
return super().form_valid(form)
I'm trying to implement the same logic for saving the comment but I get the error: name 'post_instance' is not defined
get_object() is returning the 'post_instance' variable but I can't access it.
Could you guys show me where I'm doing a mistake, thanks in advance!
You can try:
class CommentView(FormView):
template_name = 'comment.html'
form_class = CommentForm
success_url = '/'
def get_object(self):
pk = self.kwargs.get('pk')
post_instance = get_object_or_404(Post, pk=pk)
return post_instance
def form_valid(self, form):
obj = form.save(commit=False)
obj.commenter = self.request.user
obj.post = self.get_object()
obj.save()
return super().form_valid(form)