'str' object has no attribute 'socialaccount_set' django allauth - django

I am trying to change my function based views to class based views
I have this profile view as function based:
#verified_email_required
#login_required
def profile(request, username):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid and p_form.is_valid():
u_form.save()
p_form.save()
message = messages.success(request, f'Your profile has been updated')
return redirect('profile', username=username)
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
try:
profile = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request,f'Profile not found for {username}')
return redirect('home')
profile = ''
all_post_by_user = Log.objects.filter(author__username=username)
context = {
'u_form' : u_form,
'p_form' : p_form,
'profile' : profile,
'all_post_by_user' : all_post_by_user
}
return render(request, 'users/profile.html', context)
And this is my class based for the same :
class ProfileDetailView(DetailView):
model = Profile
template_name = "users/profile.html"
context_object_name = 'profile'
def get_object(self):
username = self.kwargs.get('username')
view_profile = Profile.objects.get(user__username=username)
So, I am getting this error:
profile.html:
{% extends 'log/base.html' %}
{% block content %}
{% load socialaccount %}
{% get_social_accounts profile as accounts %}
{%load crispy_forms_tags %}
<title>Error logger - Profile {{ profile.username }}</title>
<div id='profile' class="content-section card p-4">
<div class="media">
{% if profile.username == user.username %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% else %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% endif %}
<div class="media-body">
<h2 class="account-heading">{{profile.username}}</h2>
<p >{{profile.email}}</p>
<p>Created on: {{ profile.profile.created }}</p>
{% if profile.username == user.username %}
<p>Last updated on : {{ profile.profile.updated }}</p>
{% endif %}
</div>
</div>
<!-- FORM HERE -->
{% if profile.username == user.username %}
<form method='POST' autocomplete="off" enctype="multipart/form-data" >
{% csrf_token %}
<fieldset class='form-group'>
<legend class='border-bottom mb-4'>Update Profile</legend>
{{ u_form | crispy }}
{{ p_form | crispy }}
</fieldset>
<div class='form-group'>
<button class='btn btn-outline-info' type='submit'>Update</button>
</div>
</form>
{% endif %}
<div class="container border-top mt-4 pt-4">
<legend>Posts</legend>
{% for i in all_post_by_user %}
<div id="you-want-lazyload" data-lazyload="<p>Anything you want to lazyload</p>" class='m-4'>
<div class="container main m-4" style="width: 50vw;">
<a class='link' href="{% url 'log-detail' i.slug %}"><h2 >{{ i.title }}</h2></a>
<p>{{ i.content }}</p>
<p class='small'>{{ i.created }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
How to solve the error that I am getting?
I am using django allauth for social login with google
Also can someone explain why I have to query it is user__username=username?
Thanks

Ok, so the error tells us that you've got a string somewhere you aren't expecting it, because you're trying to access an attribute of a variable that is provided by allauth.
This is happening due to your exception handling here;
try:
profile = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request, f'Profile not found for {username}')
return redirect('home')
profile = ''
If a user doesn't exist, you set profile to an empty string and that gets passed in the context.
So I'd change this a little bit, to fix this error and also to avoid the confusion of looking up User objects and calling them profile (I'd assume a User to be called user or similar)
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
message = messages.warning(request, f'User not found for {username}')
return redirect('home')
user = None
all_post_by_user = Log.objects.filter(author__username=username)
context = {
'u_form' : u_form,
'p_form' : p_form,
'user' : user,
'all_post_by_user' : all_post_by_user
}
return render(request, 'users/profile.html', context)
profile.html:
{% extends 'log/base.html' %}
{% load crispy_forms_tags socialaccount %}
{% block content %}
{% get_social_accounts profile as accounts %}
<title>Error logger - Profile {{ profile.username }}</title>
<div id='profile' class="content-section card p-4">
<div class="media">
{% if profile and profile.username == user.username %}
{% if accounts %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% else %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% else %}
{% if accounts and profile %}
<img class='rounded-circle account-img' src="{{ profile.socialaccount_set.all.0.get_avatar_url }}" />
{% elif profile %}
<img class="rounded-circle account-img" src="{{ profile.profile.avatar.url }}">
{% endif %}
{% endif %}
{% if profile %}
<div class="media-body">
<h2 class="account-heading">{{profile.username}}</h2>
<p >{{profile.email}}</p>
<p>Created on: {{ profile.profile.created }}</p>
{% if profile.username == user.username %}
<p>Last updated on : {{ profile.profile.updated }}</p>
{% endif %}
</div>
</div>
<!-- FORM HERE -->
{% if profile.username == user.username %}
<form method='POST' autocomplete="off" enctype="multipart/form-data" >
{% csrf_token %}
<fieldset class='form-group'>
<legend class='border-bottom mb-4'>Update Profile</legend>
{{ u_form | crispy }}
{{ p_form | crispy }}
</fieldset>
<div class='form-group'>
<button class='btn btn-outline-info' type='submit'>Update</button>
</div>
</form>
{% endif %} <!-- end username check -->
{% endif %} <!-- end profile check -->
<div class="container border-top mt-4 pt-4">
<legend>Posts</legend>
{% for i in all_post_by_user %}
<div id="you-want-lazyload" data-lazyload="<p>Anything you want to lazyload</p>" class='m-4'>
<div class="container main m-4" style="width: 50vw;">
<a class='link' href="{% url 'log-detail' i.slug %}"><h2 >{{ i.title }}</h2></a>
<p>{{ i.content }}</p>
<p class='small'>{{ i.created }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}

Related

Django: Certain users get random 404 error

I'm facing a strange issue that I can't handle on my own.
In normal cases when users click on a link, then they are directed to a page where they can edit their hook baits (objects). However, certain users get 404 errors, but I don't know why because the page is rendered for most users.
html where the link is
<div class="row justify-content-center mx-2" >
<div class="col-12 p-0">
<ul class="list-group text-center custom-borders m-2 p-0">
{% if own_hookbaits.count == 0 %}
<a href="{% url 'user_profile:hookbaits' request.user.fisherman.fisherman_id %}" class="list-group-item" >No hook baits yet</a>
{% else %}
{% for hookbait in own_hookbaits %}
{{ hookbait.name }}
{% endfor %}
{% endif %}
</ul>
</div>
views.py
class HookBaitUpdateView(UpdateView):
model = HookBait
template_name = "user_profile/hookbaits.html"
form_class = HookBaitForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['formset'] = HookBaitFormset(queryset=HookBait.objects.filter(fisherman=self.request.user.fisherman))
return context
def post(self, request, *args, **kwargs):
formset = HookBaitFormset(request.POST)
if formset.is_valid():
return self.form_valid(formset)
else:
return self.form_invalid(formset)
def form_valid(self, formset):
instances = formset.save(commit=False)
for instance in instances:
instance.fisherman = self.request.user.fisherman
instance.save()
return super().form_valid(formset)
def form_invalid(self, formset):
return HttpResponse("Invalid")
def get_success_url(self):
return reverse('user_profile:profile', args=(self.kwargs['pk'],))
urls.py
app_name = "user_profile"
urlpatterns = [
path("profile/<int:pk>/", views.ProfileView.as_view(), name="profile"),
path("profile/<int:pk>/hookbaits/", views.HookBaitUpdateView.as_view(), name="hookbaits"),
]
rendered html
<div class="row justify-content-center m-0">
<div class="col-12 col-md-6 col-lg-4 p-0">
<div class="row mx-3 my-3 justify-content-center text-center">
<div class="card p-2 custom-borders">
<div class="card-body p-2">
<form method="POST">
{% csrf_token %}
<table class="d-flex justify-content-center">
{{ formset.management_form }}
{% for form in formset %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td class="pb-2">
{% if form.instance.pk %}{{ form.DELETE }}{% endif %}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" class="btn btn-primary w-50 mt-1" style="background-color: #00754B;" value="Mentés">
</form>
</div>
</div>
</div>
</div>
</div>
Any suggestions what the solution would be? Thanks!
there are some possibilities
the wrong link clicked like if your trying access this URL profile/25/hookbaits/
and in the data index there is no HookBait with the id of 25
in HookBaitUpdateView you are trying to get queryset=HookBait.objects.filter(fisherman=self.request.user.fisherman)
maybe there is no hookbait associate with user.fisherman
404 page mostly served when you call get_object_or_404(HookBait, pk=25)
and update view may call this method

Why forms.ModelForm loss data from FileField in Django 2.0

I have a CustomForm that extends from forms.ModelForm and use a FileField like this:
avatar = forms.FileField(required=False, label="avatar")
When I save the model, everything works, and file was saved in directory. But when I re-enter in view (file is over there), and just click in "Save", the file is lost. My views.py is:
def edit_user(request):
if request.method == "POST":
form = CustomForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
user.save()
else:
user= User\
.objects\
.get_or_create(user=request.user,
defaults={'name':request.user.first_name,
'email':request.user.email})
form = CustomForm(instance=user)
return render(request, 'user.html', {'form':form, 'user':user})
I'm using Python 3.6 and Django 2.0.
HTML:
<form method="post" action="{% url 'myprofile' %}"
class="form-horizontal" role="form"
enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
<label class="col-2 col-form-label">{{ field.label_tag }}</label>
<div class="col-10">
{% render_field field class+="form-control" %}
{% if field.errors %}
<br/>
{% for error in field.errors %}
<div class="alert alert-danger alert-dismissable">
<p><strong>{{ error|escape }}</strong></p>
</div>
{% endfor %}
{% endif %}
</div>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="{% trans 'save' %}" >
</form>

Why does the html template in django display all possible messages of incorrect input before I even tried to input something?

I implemented django user authentication following this tutorial
here is my html template:
{% block title %}Регистрация{% endblock %}
{% block additional_content %}
<p class="scheise">Регистрация</p>
{% endblock %}
{% block content %}
<div class = "sgnupform">
<form method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Sign up</button>
</form>
</div>
{% endblock %}
here is my class-based view:
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'signup.html', {'form': form})
yet somewhy messages indicative of incorrect input are displayed firsthand, before I even entered anything into a user form, and before I hit "enter":
<div class = "sgnupform">
<form method="post">
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<button type="submit">Sign up</button>
</form>
</div>
try this, as you are displaying the errors directly and not after post

Django formset not rendering with django-widget-tweaks

I am getting the error 'LoginForm' object has no attribute 'as_widget' whenever I use formset. I really do not know what is the problem as the forms renders properly with normal Django forms. I am trying to see what characteristics in the formset is giving this problem with django-widget-tweaks, but up until now it is hard to figure out. I am getting the error at {% render_field field class="form-control" placeholder=field.label %} in the HTML code.
forms.py:
class LoginForm(ModelForm):
user_login = forms.HiddenInput()
prefix = 'prefix_login'
class Meta:
model = Usermie
fields = ['email', 'password']
widgets = {'password': forms.PasswordInput(),
'email': forms.EmailInput()}
views.py
def manage_articles(request):
article_formset = formset_factory(LoginForm)
book_formset = formset_factory(SignUpForm)
if request.method == 'POST':
if 'login' in request.POST:
login = article_formset(request.POST, request.FILES, prefix='login')
if login.is_valid():
email = request.POST.get('prefix_login-email', '')
password = request.POST.get('prefix_login-password', '')
# Return a user_obj object if the username and password are valid
# otherwise it will return null, the null variable is called None in python
user_obj = auth.authenticate(email=email, password=password)
# return HttpResponse("inside form if condition")
if user_obj is not None:
if user_obj.is_active:
login_usermie(request, user_obj)
return HttpResponseRedirect('/home/')
else:
# pass
return HttpResponse("Your account is inactive.")
elif 'signup' in request.POST:
signup = book_formset(request.POST, request.FILES)
if signup.is_valid():
pass
else:
login = article_formset
signup = book_formset
return render(request, 'usermie/formtest.html', {
'login': login,
'signup': signup,
})
HTML:
<div class="navbar navbar-default nav-links navbar-static-top page-nav">
<div class="container">
<a class="mini-navbar navbar-brand" href="/">
<img src="http://i.imgur.com/GAQSCtB.png" width="25"
alt="Driven Car Sales Logo"
class="img-rounded logo-nav mini-navbar" />
</a>
<ul class="nav navbar-nav nav-form-out pull-right">
<li>
<form class="navbar-form navbar-form-out login" action="" method="POST">
{% csrf_token %}
{% load widget_tweaks %}
{% for field in login %}
{% if login.errors %}
<div class="form-group">
<label class="sr-only" for="{{ field.auto_id }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
{% if field == login.password %}
{% for hidden in field.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
<div class="help-block with-errors">{{ field.errors }}</div>
</div>
{% else %}
<div class="form-group">
<label class="sr-only" for="{{ field.auto_id }}">{{ field.label }}</label>
{% render_field field class="form-control" placeholder=field.label %}
{% if field == login.password %}
{% for hidden in field.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
</div>
{% endif %}
{% endfor %}
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
<button type="submit" name="action" value="login" class="btn btn-default">Sign in</button>
</form>
</li>
</ul>
</div>
<form class="signup" method="POST" action="">
{% csrf_token %}
{{ signup.as_p }}
<button name='action' value='signup' type="submit">Sign up</button>
</form>
login variable in template is a formset. So when you do following:
{% for field in login %}
{% render_field field class="form-control" placeholder=field.label %}
{% endfor %}
you have form as field value and not a field.
Try do this:
{% for form in login %}
{% for field in form %}
{% render_field field class="form-control" placeholder=field.label %}
{% endfor %}
{% endfor %}

modal form embedded in html does not work in django

I'm making an application for food recipes and am trying to do the same html in the recipe and include comments in a modal window, the problem is that when I give I submit template fails and does not save the comment on the data base
urls.py
urlpatterns = patterns('recetas.apps.menus.views',
url(r'^recetas/$','recetas_view',name='vista_recetas'),
url(r'^reporte/$','reporte_receta',name='receta_reporte'),
url(r'^receta/(?P<id_receta>\d+)$','detalle_receta', name='vista_detalle'),
)
The html code that calls this url
<td><a href='/receta/{{ receta.id }}'>{{ receta.titulo }}</a></td>
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
{% extends 'base.html' %}
{% block titulo %}{{ receta.titulo }}{% endblock titulo %}
{% block estatico %}
<link rel='stylesheet' href='{{ STATIC_URL }}css/receta.css' type='text/css'>
<link rel='stylesheet' href='{{ STATIC_URL }}css/modal.css' type='text/css'>
<script type='text/javascript'>
function despliegaModal(valor) {
var elem = document.getElementById("bgVentanaModal");
elem.style.visibility = valor;
}
</script>
{% endblock estatico %}
{% block contenido %}
<div id="bgVentanaModal">
<div id="ventanaModal">
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input name="cancel" type="submit" value="Cancelar">
</form>
</div>
</div>
<div id=receta>
<div id="nombre_receta">
<h1>{{receta.titulo|title}}</h1>
<hr>
</div>
<div id='ingredientes'>
<h2>Ingredientes</h2>
<p>{{ receta.ingredientes }}</p>
</div>
<div id='imagen'>
<img src='{{MEDIA_URL}}{{receta.imagen}}' width="480" height="300" >
</div>
<div id='preparacion'>
<h2>Preparación</h2>
<p>{{ receta.preparacion }}</p>
</div>
<div id='comentarios'>
<h2>Comentarios</h2>
{% for item in comentarios %}
<p>{{ item.texto}}</p>
{% empty %}
<p>Sin Comentarios registrados</p>
{% endfor %}
{% if user.is_authenticated %}
Agregue su comentario
{% endif %}
</div>
<div id="pie">
<hr>
<p>Receta Registrada el {{ receta.tiempo_registro|date:'SHORT_DATETIME_FORMAT' }} por {{ receta.usuario }}</p>
</div>
</div>
{% endblock contenido %}
everything works until I give the cancel key, does not validate the POST.
I believe the problem is in your view.py. Specifically in this part:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
That if will never result in a False value and, hence, your comment will never be saved. This has to do with how the dict.get function works:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
So, if you click Grabar you'll get the default value (id_receta). Try the following instead:
if request.POST.get('cancel'): # Default to None
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
A workaround would be just using a button with some JavaScript to redirect when you click Cancelar in your template:
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
# if request.POST.get('cancel', id_receta):
# return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
...
...
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ dato.id }}'"/>>
</form>
...
...
Of course, you should use get_absolute_url instead of hardcoding URLs.
Thanks for help me Cesar, your answer help me, but my error is in the variable in receta.html
is {{ receta.id }} and in the button is the same the correct is
<form action="/receta/{{ receta.id }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar"/>
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ receta.id }}'"/>
</form>
Thanks for your help and a friend who found the error