I have found here on stackoverflow a solution to extend django-registration with new fields using signals. Here's the link : http://dmitko.ru/?p=546 .
I have created extended profile model, extended form, added required options to settings , defined urls and the proper form is displayed but only normal User (from auth module) is created. Why is that happening ?
account.models :
from django.db import models
from django.contrib.auth.models import User
from registration.signals import user_registered
import hashlib
class InheritedProfile(models.Model):
first_name = models.CharField("Name", max_length=50, blank=True, null=True)
last_name = models.CharField("Last name", max_length=50, blank=True, null=True)
pid = models.CharField("PESEL", max_length=11, blank=True, null=True)
street = models.CharField("Street", max_length=50, blank=True, null=True)
number = models.CharField("Flat/house number", max_length=10, blank=True, null=True)
code = models.CharField("Zip ", max_length=6, blank=True, null=True)
city = models.CharField("City", max_length=50, blank=True, null=True)
class Meta:
abstract=True
class UserProfile(InheritedProfile, User):
def upload_path(self, field_attname):
filename = hashlib.md5(field_attname).hexdigest()[:4] + "_" + field_attname
return "uploads/users/%s" % (filename,)
image = models.ImageField(upload_to=upload_path, verbose_name="Image", blank=True, null=True)
def user_created(sender, user, request, **kwargs):
form = ExtendedRegistrationForm(request.POST)
extended_user = UserProfile(user=user)
extended_user.is_active = False
extended_user.first_name = form.extended_user['first_name']
extended_user.last_name = form.extended_user['last_name']
extended_user.pid = form.extended_user['pid']
extended_user.image = form.extended_user['image']
extended_user.street = form.extended_user['street']
extended_user.number = form.extended_user['number']
extended_user.code = form.extended_user['code']
extended_user.city = form.extended_user['city']
extended_user.save()
user_registered.connect(user_created)
I need this InheritedProfile to be abstract as other models will use the same fields.
account.forms
from django import forms
#import strings
from registration.forms import RegistrationForm
from models import UserProfile, InheritedProfile
class ExtendedRegistrationForm(RegistrationForm):
first_name = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="First name")
last_name = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="Last name")
pid = forms.RegexField(regex=r'^\d{11}', max_length=11 ,widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)))
image = forms.ImageField(label="Image",)
street = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="Street")
number = forms.CharField(widget=forms.TextInput, label="House/flat number")
code = forms.RegexField(regex=r'^\d{2}[-]\d{3}', max_length=6, widget=forms.TextInput(attrs=attrs_dict), label="Postal code")
city = forms.CharField(widget=forms.TextInput, label="City")
and options added to settings :
AUTH_PROFILE_MODULE = 'account.UserProfile'
ACCOUNT_ACTIVATION_DAYS = 7
finally this is how the registration signal looks like :
from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user", "request"])
EDIT:
Indentation of user_created changes nothing until I've tried changing
user_registered.connect(user_created)
to
user_registered.connect(user_created, sender=UserProfile)
Now I was getting :
"SMTPServerDisconnected
Exception Location: /bin/python-2.6.1/lib/python2.6/smtplib.py in getreply, line 340 "
Traceback:
File "/home/fandrive/site-packages/django/core/handlers/base.py" in get_response
92. response = callback(request, *callback_args, **callback_kwargs)
File "/home/fandrive/registration/views.py" in register
47. new_user = backend.register(request, **form.cleaned_data)
File "/home/fandrive/registration/backends/default/__init__.py" in register
20. password, site)
File "/home/fandrive/site-packages/django/db/transaction.py" in _commit_on_success
240. res = func(*args, **kw)
File "/home/fandrive/registration/models.py" in create_inactive_user
80. registration_profile.send_activation_email(site)
File "/home/fandrive/registration/models.py" in send_activation_email
256. self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
File "/home/fandrive/site-packages/django/contrib/auth/models.py" in email_user
271. send_mail(subject, message, from_email, [self.email])
File "/home/fandrive/site-packages/django/core/mail.py" in send_mail
390. connection=connection).send()
File "/home/fandrive/site-packages/django/core/mail.py" in send
266. return self.get_connection(fail_silently).send_messages([self])
File "/home/fandrive/site-packages/django/core/mail.py" in send_messages
172. sent = self._send(message)
File "/home/fandrive/site-packages/django/core/mail.py" in _send
186. email_message.message().as_string())
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in sendmail
708. self.rset()
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in rset
438. return self.docmd("rset")
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in docmd
363. return self.getreply()
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in getreply
340. raise SMTPServerDisconnected("Connection unexpectedly closed")
Exception Type: SMTPServerDisconnected at /user/register/
Exception Value: Connection unexpectedly closed
Even though I'm using dummy email backend at the moment. Commenting out sending mail function upon registration solved this problem but still my extended user is not created.
May be the problem is in the way how you connect to the signal? In my solution in was:
def user_created(sender, user, request, **kwargs):
form = UserRegistrationForm(request.POST)
data = profile.Profile(user=user)
data.city_id = form.data["city"]
data.save()
from registration.signals import user_registered
user_registered.connect(user_created)
and in yours:
from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user", "request"])
Also, I would switch on logging to ensure that your method is called. My solution works fine in the production, if you need I can look for other details.
Related
I would really appreciate some help on this because I'm completely stuck. I've started up a simple django app (trying to make an instagram clone). However, when I try to display the post objects (which I created in the django admin page) nothing is displayed in index.html, so I tried printing out the objects in the views.py and it's returning to me an empty query set. I don't quite understand what I'm doing wrong and why I can't access the objects? When I print out the username I am able to get that, but then nothing for both post and stream objects. Please I'm so stuck any advice would be appreciated.
views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.template import loader
from django.http import HttpResponse
# Create your views here.
from post.models import post, stream
#login_required
# we are getting all of the string objects that are created for the user
def index(request):
user = request.user
print(user)
posts = stream.objects.filter(user=user)
print(posts)
group_ids = []
#then looping through and getting post id to a list
for posted in posts:
group_ids.append(posted.post_id)
print(group_ids)
#then filtering them so that you can display it in the index
#selecting a specific post by id
post_items = post.objects.filter(id__in=group_ids).all().order_by('-date')
template = loader.get_template('index.html')
context = {'post_items' : post_items}
return(HttpResponse(template.render(context, request)))
models.py
from django.db import models
from django.contrib.auth.models import User
import uuid
# Create your models here.
from django.db.models.signals import post_save
from django.utils.text import slugify
from django.urls import reverse
def user_directory_path(instance,filename):
# this file is going to be uploaded to the MEDIA_ROOT /user(id)/filename
return('user_{0}/{1}'.format(instance.user.id,filename))
class tag(models.Model):
title = models.CharField(max_length = 80, verbose_name = 'tag')
slug = models.SlugField(null = False, unique = True)
class Meta:
verbose_name = 'tag'
verbose_name_plural = 'tags'
# for when people click on the tags we can give them a url for that
# def get_absolute_url(self):
# return(reverse('tags', args = [self,slug]))
def __str__(self):
return(self.title)
def save(self,*args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return(super().save(*args, **kwargs))
class post(models.Model):
# will create a long id for each post
id = models.UUIDField(primary_key=True, default = uuid.uuid4, editable = False)
image = models.ImageField(upload_to = user_directory_path, verbose_name= 'image', null = True)
caption = models.TextField(max_length = 2000, verbose_name = 'caption')
date = models.DateTimeField(auto_now_add = True)
tags = models.ManyToManyField(tag, related_name='tags')
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField()
def get_absolute_url(self):
return reverse('postdetails', args=[str(self.id)])
# def __str__(self):
# return(self.user.username)
class follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='follower')
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='following')
class stream(models.Model):
following = models.ForeignKey(User, on_delete=models.CASCADE, related_name='stream_following')
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(post, on_delete=models.CASCADE)
date = models.DateTimeField()
def add_post(sender, instance,*args, **kwargs):
# here we are filtering all the users that are following you
post = instance
user = post.user
followers = follow.objects.all().filter(following=user)
for follower in followers:
streams = stream(post=post, user=follower.follower, date = post.date, following = user)
streams.save()
post_save.connect(stream.add_post, sender=post)
output from print statements
user
<QuerySet []>
[]
I figured it out. It wasn't an issue with the code, but the way that I was creating posts in the admin panel. So because you can only view posts from users that you are following, the posts that I was creating weren't showing up. So I had to create another user, and follow that user, then have the new user post something. Then the post shows up in the page!
Please help me to find a solution to this error, whene using django-import-export
here is my code :
Models :
class ChartOfAccounts(models.Model):
code = models.CharField('code plan comptable', max_length=20, unique=True)
name = models.CharField('plan comptable', max_length=100)
def __str__(self):
return self.code
class Company(models.Model):
code = models.CharField('code société', max_length=20, unique=True)
name = models.CharField('société', max_length=100)
addr = models.CharField('adresse', max_length=100, blank=True, null=True)
chart_of_accounts = models.ForeignKey(ChartOfAccounts, on_delete=models.CASCADE, verbose_name='code plan comptable')
def __str__(self):
return self.code
class GLAccount(models.Model):
class Meta:
unique_together = (('code', 'chart_of_accounts'),)
code = models.CharField('code compte comptable', max_length=10)
chart_of_accounts = models.ForeignKey(ChartOfAccounts, on_delete=models.CASCADE, verbose_name='code plan comptable')
name = models.CharField('compte comptable', max_length=100, help_text='text descriptif du compte comptable')
def __str__(self):
return f'{self.code}, {self.chart_of_accounts}'
class CompanyAccount(models.Model):
company = models.ForeignKey(Company, verbose_name='code société', on_delete=models.CASCADE)
gl_account = models.ForeignKey(GLAccount, verbose_name='compte comptable', on_delete=models.CASCADE)
Resources :
class CompanyAccountResource(ModelResource):
class Meta:
model = models.CompanyAccount
fields = ('company', 'gl_account',)
exclude = ('id',)
import_id_fields = ('company', 'gl_account',)
skip_unchanged = False
report_skipped = False
# fields
company = Field(
column_name=Meta.model._meta.get_field('company').verbose_name,
attribute='company',
widget=ForeignKeyWidget(models.Company, field='code')
)
gl_account = Field(
column_name=Meta.model._meta.get_field('gl_account').verbose_name,
attribute='gl_account',
widget=ForeignKeyWidget(models.GLAccount, field='code')
)
def get_export_order(self):
export_fields = ['company', 'gl_account', ]
return export_fields
My data is :
Company model data here
ChatOfAccounts model data here
GLAccount model data here
CompanyAccountResource Excel canvas to import data
the problem :
a GLAccount code may apear in 2 chart of accounts, each related to one company, and when try to import data from excel to CompanyAccountResource, the error below will apear :
Line number: 1 - get() returned more than one GLAccount -- it returned 2!
S001, 600000
Traceback (most recent call last):
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\resources.py", line 639, in import_row
instance, new = self.get_or_init_instance(instance_loader, row)
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\resources.py", line 334, in get_or_init_instance
instance = self.get_instance(instance_loader, row)
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\resources.py", line 327, in get_instance
return instance_loader.get_instance(row)
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\instance_loaders.py", line 29, in get_instance
params[field.attribute] = field.clean(row)
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\fields.py", line 66, in clean
value = self.widget.clean(value, row=data)
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\import_export\widgets.py", line 396, in clean
return self.get_queryset(value, row, *args, **kwargs).get(**{self.field: val})
File "C:\Users\Leo\PycharmProjects\Django\DjangoSnippets\venv\lib\site-packages\django\db\models\query.py", line 433, in get
raise self.model.MultipleObjectsReturned(
app1.models.GLAccount.MultipleObjectsReturned: get() returned more than one GLAccount -- it returned 2!
The error is occurring because you are defining import_id_fields which don't uniquely identify an object.
import_id_fields is used by the import workflow to identify an existing model instance for update. In your case, the combination of 'company', 'gl_account' is identifying multiple rows in the CompanyAccountResource.
If you need your import logic to update existing instances, then you will have to find a way to uniquely identify the row for update.
i'm sending notifications to a user via django notifications. And i have username regex working on the html so anyone comments with #username it will post and the html is linkable so click on the #username it will take him to the username profile page. Now i am using django signals to match the username and print out the username. but when i use notify to send the notification. it does not work.
models.py:
class Comment(models.Model):
post = models.ForeignKey(post, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE)
reply = models.ForeignKey('Comment', null=True, related_name='replies', on_delete=models.CASCADE)
content = models.TextField()
image = models.ImageField(upload_to='comments-pics', null=True, blank=True)
voice_record = models.FileField(upload_to='voice-comments', null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__ (self):
return '{}.{}'.format(self.post.title, str(self.user.username))
def save(self, *args, **kwargs):
super(Comment, self).save(*args, **kwargs)
def Comment_save_receiver(sender, instance, created, *args,**kwargs):
if created and not instance.parent:
user_regex = r'#(?P<username>[\w.#+-]+)'
m = re.search(user_regex, instance.content)
if m:
try:
recipient = User.objects.get(username=m.group('username'))
except (User.DoesNotExist, User.MultipleObjectsReturned):
pass
else:
notify.send(instance.user, recipient=recipient, actor=instance.user, verb='mention you in a post', target=instance, nf_type='tagged_by_one_user')
post_save.connect(Comment_save_receiver, sender=post)
the problem has been solved. i did wrong with the signal portion. it will be:
def comment_save_receiver(sender, instance, created, *args,**kwargs):
if created:
user_regex = r'#(?P<username>[\w.#+-]+)'
m = re.search(user_regex, instance.content)
if m:
try:
recipient = User.objects.get(username=m.group('username'))
except (User.DoesNotExist, User.MultipleObjectsReturned):
pass
else:
notify.send(instance.user, recipient=recipient, actor=instance.user, verb='mention you in a post', target=instance.post, nf_type='tagged_by_one_user')
post_save.connect(comment_save_receiver, sender=Comment)
I've been trying to implement a file size validator in django on a filefield, but I can't really make it work.
Everything works right until I add this validator. After I add it, I can't upload files anymore at all. The error says "File field does not have a full_clean attribute".
views.py
from django.shortcuts import render, get_object_or_404
from .models import Oferta, CV
from django.contrib import messages
from django.core.paginator import Paginator
def incarcarecv(req):
context = {
'title': "Incarcare CV | Best DAVNIC73"
}
if req.method == 'POST':
nume = req.POST['nume']
prenume = req.POST['prenume']
telefon = req.POST['telefon']
email = req.POST['email']
cv = req.FILES['CV']
if(req.user.is_authenticated):
cv_upload = CV(
solicitant=req.user,
nume=nume,
prenume=prenume,
telefon=telefon,
emailContact=email
)
cv_upload.CVFile.full_clean()
cv_upload.CVFile.save(cv.name, cv)
cv_upload.save()
req.user.profile.cvuri.append(cv_upload.id)
req.user.profile.save()
messages.success(req, 'CV depus cu succes!')
else:
messages.error(req, 'Trebuie sa fii logat pentru a depune CV-ul!')
return render(req, "../templates/pagini/incarcare-cv.html", context)
models.py
from django.db import models
from django.contrib.auth.models import User
from .validators import validate_file_size
# Create your models here.
class Oferta(models.Model):
solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
dataSolicitare = models.DateField(auto_now_add=True)
cor = models.CharField(max_length=25)
denumireMeserie = models.CharField(max_length=12)
locuri = models.IntegerField()
agentEconomic = models.CharField(max_length=50)
adresa = models.CharField(max_length=150)
dataExpirare = models.DateField()
experientaSolicitata = models.CharField(max_length=200)
studiiSolicitate = models.CharField(max_length=200)
judet = models.CharField(max_length=20)
localitate = models.CharField(max_length=25)
telefon = models.CharField(max_length=12)
emailContact = models.EmailField(max_length=40)
rezolvata = models.BooleanField(default=False)
def __str__(self):
return self.cor
class CV(models.Model):
solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
dataUploadCV = models.DateField(auto_now_add=True)
nume = models.CharField(max_length=12)
prenume = models.CharField(max_length=12)
telefon = models.CharField(max_length=12)
emailContact = models.EmailField(max_length=40)
CVFile = models.FileField(upload_to='documents/%d/%m/%Y', validators=[validate_file_size])
rezolvata = models.BooleanField(default=False)
def __str__(self):
return self.nume + " " + self.prenume + ": " + str(self.CVFile)
validators.py
from django.core.exceptions import ValidationError
def validate_file_size(value):
filesize=value.size
if filesize > 5000000:
raise ValidationError("Maximum 5MB!")
I just can't seem to get why. Can you help me fix my code?
As far as I know, .full_clean() runs some default django validators + the ones set in the model.
But actually it does not work.
Exception Value:
'FieldFile' object has no attribute 'full_clean'
Can you explain to me why is this happening and how can I make my validator run?
Thanks.
//by the way, someone recommended to change the order of the lines like this -
cv_upload.CVFile.save(cv.name, cv)
cv_upload.CVFile.full_clean()
but it does not work anyway.
As the error says, full_clean() isn't a method of a model field. It's a method of the model itself.
cv_upload.full_clean() works.
But you should just initialise your cv_upload with the file directly:
cv_upload = CV(
solicitant=...,
...,
CVFile=cv)
then you don't have to save the file separately, see the docs.
Also, you're running full_clean() but not catching any exceptions. What happens if validation fails? A ValidationError will be thrown. If you don't catch it, your view will return a HTTP 500 error (it will just crash).
So wrap it in a try ... except clause:
try:
cv_upload.full_clean()
except ValidationError as e:
messages.error(request, e)
else:
cv_upload.save()
messages.success(request, "yeah!")
I've created a new app called users with the model Profile. For authentication I'm using django-allauth with Facebook and Google providers. Once user is logged in, I'd like to create a profile with some additional information populated from social providers, like: full_name, email, picture.
Here is what I have in the models.py:
from django.contrib.auth.models import User
from django.dispatch import receiver
from allauth.account.signals import user_signed_up
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
full_name = models.CharField(default=None, max_length=255)
email = models.CharField(default=None, max_length=500)
picture = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return self.user.username
#receiver(user_signed_up)
def populate_profile(sociallogin, user, **kwargs):
user.profile = Profile()
if sociallogin.account.provider == 'facebook':
user_data = user.socialaccount_set.filter(provider='facebook')[0].extra_data
picture_url = "http://graph.facebook.com/" + sociallogin.account.uid + "/picture?type=large"
email = user_data['email']
full_name = user_data['name']
if sociallogin.account.provider == 'google':
user_data = user.socialaccount_set.filter(provider='google')[0].extra_data
picture_url = user_data['picture']
email = user_data['email']
full_name = user_data['name']
user.profile.picture = picture_url
user.profile.email = email
user.profile.full_name = full_name
user.profile.save()
While logging with Facebook, I'm getting the following error message:
[WinError 10061] No connection could be made because the target machine actively refused it
And when I try to log in with Google, I receive the following:
DataError at /accounts/google/login/callback/
value too long for type character varying(100)
Can someone please tell me what's wrong with my code? Thanks in advance.
Issues are now solved. First error message I solved by adding:
ACCOUNT_EMAIL_VERIFICATION = None
And for the second one I had to add max_length=255 for the picture:
picture = models.ImageField(default='default.jpg', upload_to='profile_pics', max_length=255)