I am trying get a picture link from a facebook account but get this message:
django.db.utils.IntegrityError: UNIQUE constraint failed:
user_profile.user_id
I can see a picture link in console, but I cannot save it in user profile.
here is my model.py when I'm trying to do that.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from allauth.account.signals import user_signed_up, user_logged_in
from allauth.socialaccount.models import SocialAccount
import hashlib
try:
from django.utils.encoding import force_text
except ImportError:
from django.utils.encoding import force_unicode as force_text
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
related_name='userprofile')
city = models.CharField(max_length=30, blank=True)
about = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', verbose_name='Images',
blank=True)
sound = models.BooleanField(default=False)
points = models.DecimalField(max_digits=4, decimal_places=2, default=0.00)
energy = models.IntegerField(default=0)
avatar_url = models.URLField(max_length=500, blank=True, null=True)
class Meta:
db_table = 'user_profile'
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
def __str__(self):
return str(self.user)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.userprofile.save()
##receiver(user_logged_in)
#receiver(user_signed_up)
def set_initial_user_names(request, user, sociallogin=None, **kwargs):
preferred_avatar_size_pixels = 25
if sociallogin:
if sociallogin.account.provider == 'facebook':
picture_url = "http://graph.facebook.com/{0}/picture?width={1}&height={1}".format(
sociallogin.account.uid, preferred_avatar_size_pixels)
profile = UserProfile(user=user, avatar_url=picture_url)
#profile = UserProfile.objects.get(user=user)
#profile.avatar_url = picture_url
profile.save()
If I am doing like that at the end:
#profile = UserProfile(user=user, avatar_url=picture_url)
profile = UserProfile.objects.get(user=user)
profile.avatar_url = picture_url
profile.save()
I am not gettin any message in the console, but user profile doesn't save.
This line profile = UserProfile(user=user, avatar_url=picture_url) is causing the problem as you are trying to create a new instance of profile which already exists. The profile becomes unique because of OneToOne field in your UserProfile model.
And you don't need to get the user from the database because set_initial_user_names function is already passing the registered user to you as a parameter. So just do user.userprofile. Then you can just update the user with new information.
Also I would suggest you to download the picture from the url provided and then save it in your image field of your model like this:
import urllib
from django.core.files import File
# for python 2: result = urllib.urlretrieve(picture_url)[0]
result = urllib.request.urlretrieve(picture_url)[0] # for python 3
user.userprofile.avatar.save('test.jpg', File(open(result, 'rb')))
user.userprofile.save()
Related
folder structure
enter image description here
models.py from face_detect
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Profile(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
mobile = models.CharField(max_length=10,null=True)
add = models.CharField(max_length=10,null=True)
image = models.FileField(null=True)
def __str__(self):
return self.user.username
models.py from otp
from django.db import models
from django.contrib.auth.models import User
from face_detect.models import Profile
import random
# Create your models here.
class Code(models.Model):
number = models.CharField(max_length=5, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return str(self.number)
#otp verification
def save(self, *args, **kwargs):
number_list = [x for x in range(10)]
code_items = []
for i in range(5):
num = random.choice(number_list)
code_items.append(num)
code_string = "".join(str(item) for item in code_items)
self.mobile = code_string
super().save(*args,**kwargs)
signals.py from otp
from face_detect.models import Profile
from django.contrib.auth.models import User
from .models import Code
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def post_save_generate_code(sender, instance, created, *args, **kwargs):
if created:
Code.objects.create(user=instance)
apps.py from otp
from django.apps import AppConfig
class OtpConfig(AppConfig):
name = 'otp'
def ready(self):
import otp.signals
init.py from otp
default_app_config = 'otp.apps.OtpConfig'
admin.py from otp
from django.contrib import admin
from .models import Code
# Register your models here.
admin.site.register(Code)
code seen in http://127.0.0.1:8000/admin/otp/code/
enter image description here
code is not visible.
how can i make the code visible so i can use it for otp verification while login.
Thanks in advance
In admin page you will see the __str__ method, so there seems to be nothing wrong with your code most probably your code instance's value is "", Also one other thing
def __str__(self):
return str(self.number)
you dont need to cast it to str here its already char field
and another thing is here:
def __str__(self):
return self.user.username
in Profile model you made user nullable so this means not all the profile instances might not have user so you will get NoneType has no attribute username
change it to this to prevent this errors:
def __str__(self):
return self.user.username if self.user else ""
I have been using a Video model related with the user on a cascade basis.
from django.conf import settings
class Video(models.Model):
uuid = models.CharField(max_length=255, default="")
title = models.CharField(max_length=255, default="")
description = models.CharField(max_length=5000, default="")
privacy = models.CharField(max_length=10, default="public")
category = models.CharField(max_length=50, default="General")
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=None)
def delete(self, *args, **kwargs):
publisher = pubsub_v1.PublisherClient()
topic_name = '...'
message_to_publish = self.path
publisher.publish(topic_name, data=message_to_publish.encode('utf-8'), spam='eggs')
logging.info("Sending pubsub to delete folder : {0}".format(message_to_publish))
super(Video, self).delete(*args, **kwargs)
When I trigger a delete on the user,
def clear_user(request):
user = request.user
user.delete()
This does not trigger the overloaded delete function. How can I achieve that overloaded delete function to be called on user delete?
because the related objects are deleted with sql in database directly, it do not call the delete method of the related model, so it does not work to override delete method. it could be one way to use pre_delete or post_delete signal.
# signals.py
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.contrib.auth import get_user_model
User=get_user_model()
#receiver(pre_delete, sender=User)
def user_delete_callback(sender, **kwarg):
# do something
print('user delete callback:', kwarg)
# apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
from . import signals
I want to create an auto-generated membership id of a user in the profile table based on the current date and username. User table has OneToOneField relationship with the profile table. So when I create a user, I have to put username in the registration form. The signals.py creates a profile row in the table for the user. I want when the profile is created it would have a membership id which is the mix of current date and username. My code is as follow:
singlas.py
from django.db.models.signals import post_save, pre_save
from .models import Ext_User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=Ext_User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
models.py
class Profile(models.Model):
user = models.OneToOneField(Ext_User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics', null=True, blank=False)
membership_id = models.CharField(max_length=50, default='', null=True, blank=True)
def __str__(self):
return f'{self.user.username} Profile'
I have got some guideline to user pre_save into signals.py but don't understand how to figure out.
You can try this
#receiver(post_save, sender=Ext_User)
def create_profile(sender, instance, created, **kwargs):
if created:
profile = Profile()
profile.membership_id = str(instance.username) + str(datetime.datetime.now())
profile.user_id = instance.pk
profile.save()
format DateTime as your desired format
I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!
I have a video model in django. Currently when a video is saved, the current logged user is not saved in the model (Other fields have a value, except the user field). The form uses a generic create django view.
I would like to know how to save the current logged user when a new video is saved?
multimedia/models.py
from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
from django.core.exceptions import PermissionDenied
from django.db.models.signals import post_save
from django.contrib.auth.decorators import login_required
class Video(models.Model):
user = models.ForeignKey(User, related_name='+',blank=True, null=True)
title = models.CharField(max_length=200)
description = models.TextField()
created = models.DateTimeField('date created', auto_now_add=True, blank=False)
file_url = models.CharField(max_length=2000, blank=True)
file_name = models.CharField(max_length=255, blank=True)
file_uploaded = models.DateTimeField('date file uploaded', null=True, blank=True)
file_upload_speed = models.FloatField(null=True, blank=True)
file_size = models.IntegerField(null=True, blank=True)
def has_file(self):
return len(self.file_url) > 0
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('multimedia_video_detail', [self.id])
class VideoForm(ModelForm):
class Meta:
model = Video
# fields = ('title', 'description')
exclude = ('file_url', 'file_name', 'file_uploaded','file_upload_speed', 'file_size')
multimedia/views.py
from django.conf.urls.defaults import patterns, include, url
from models import Video, VideoForm
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$','django.views.generic.list_detail.object_list',{ 'queryset': Video.objects.all() }, name='multimedia_video_list'),
url(r'^new$', 'django.views.generic.create_update.create_object',{ 'model': Video },name='multimedia_video_new'),
url(r'^(?P<object_id>[\d]*)$', 'django.views.generic.list_detail.object_detail',{ 'queryset': Video.objects.all() }, name='multimedia_video_detail'),
url(r'^(?P<object_id>[\d]*)/edit$','django.views.generic.create_update.update_object',{ 'form_class': VideoForm }, name='multimedia_video_edit'),
url(r'(?P<object_id>[\d]*)/delete$', 'django.views.generic.create_update.delete_object', { 'model': Video, 'post_delete_redirect': '/videos' }, name='multimedia_video_delete'),
url(r'^(?P<object_id>[\d]*)/upload$','multimedia.views.upload_video',name='multimedia_video_upload'),
url(r'^(?P<object_id>[\d]*)/upload/done$','multimedia.views.upload_video_done',name='multimedia_video_upload_done'),
)
Thanks for any help to solve this issue
Instead of directly using the generic creation view, you need to use a wrapper around it that pulls the current user out of the request. Additionally, you create a model form that accepts the user, and overrides the save() method to set the user value on the model instance.
def VideoForm(user):
class _wrapped(forms.ModelForm):
class Meta:
model = models.Video
def save(self, *args, **kwargs):
self.instance.user = user
super(_wrapped, self).save(*args, **kwargs)
return _wrapped
#login_required
def create(request):
return django.views.generic.create_update.create_object(form_class=VideoForm(request.user), name='multimedia_video_new')