Please could you me why I get this error message while displaying "fav" in my template
QuerySet object has no attribute game_id
I tried to replace game_id by game, id_game but nothing...
view.py
from django.contrib import messages
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout
from django.shortcuts import render
from start.models import Games, FavoriteGames
import urllib, json
def view_recap(request):
if request.user.is_authenticated():
username = request.user.username
id_user = request.user.id
fav = FavoriteGames.objects.filter(user_id=id_user).game_id
return render(request, 'recap.html', locals())
else:
from start.views import view_logoff
from start.views import view_logon
messages.add_message(request, messages.INFO, 'Vous devez être connecté pour accéder à cette page.')
return redirect(view_logon)
models.py
from django.db import models
from django.conf import settings
# Create your models here.
class Games(models.Model):
guid = models.CharField(max_length=100, unique=True, null=False, verbose_name="GUID")
title = models.CharField(max_length=100, null=False, verbose_name="Titre")
logo = models.CharField(max_length=100, null=True, blank=True, verbose_name="Logo")
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date de création")
update = models.DateTimeField(auto_now=True, verbose_name="Dernière modification")
def __str__(self):
return self.title
class FavoriteGames(models.Model):
game = models.ForeignKey('Games')
user = models.ForeignKey(settings.AUTH_USER_MODEL)
When you loop through the queryset you can access the game_id for each instance. You can't access it on the queryset.
You can loop through the queryset in the view,
favs = FavoriteGames.objects.filter(user_id=id_user)
for fav in favs:
game_id = game_id
or in the template:
{% for fav in favs %}
{{ fav.game_id }}
{% endfor %}
If you only need the game_ids from the queryset, you could use values_list:
game_ids = FavoriteGames.objects.filter(user_id=id_user).values_list('game_id', flat=True)
filter will return Queryset.So use get instead of filter. If multiple objects are there use filter, but you need to loop over that queryset to get each objects.
Related
I m learning Django 2.2, I am trying to a model from named sKills base on a parent model named Profile:
But I have this error :
DoesNotExist at /skills/
Profile matching query does not exist.
Request Method: GET
Request URL: http://127.0.0.1:8080/skills/
Django Version: 2.2
Exception Type: DoesNotExist
Exception Value:
Profile matching query does not exist.
in Skills => models.py:
from django.db import models
from profiles.models import Profile
from django.core.validators import MaxValueValidator, MinValueValidator
# Create your models here.
class Skill(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
name = models.CharField(max_length=220)
score = models.PositiveIntegerField(
validators=[MinValueValidator(1), MaxValueValidator(5)])
def __str__(self):
return "{}-{}-{}".format(self.user, self.name, self.score)
in Skills => Views.py:
# Create your views here.
def skill_view(request):
user_id = request.user.id
profile = Profile.objects.get(pk=user_id)
#profile = get_object_or_404(Profile, pk=user_id)
SkillFormset = inlineformset_factory(Profile, Skill,fields='__all__',extra=1)
formset = SkillFormset( instance=profile)
context = {
'formset': formset
}
return render(request,'skills/add.html',context)
In Skills => urls.py:
app_name = 'skills'
urlpatterns = [
path('', skill_view, name='my-skills'),
]
In Skills => templates =>skills => add.html:
{% extends 'base.html' %}
{% block title %}my skills{% endblock title %}
{% block content %}
<form action="" method="POST">
{{formset}}
</form>
{% endblock content %}
In Profile => Models:
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
# Create your models here.
class Profile(models.Model):
name = models.ForeignKey(User, on_delete=models.CASCADE)
website = models.URLField(blank=True)
avatar = models.ImageField(upload_to='uploads/img', validators=[FileExtensionValidator(allowed_extensions=['png'])], blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
#property
def get_created(self):
return self.created.strftime("%m/%d/%Y, %H:%M:%S")
def __str__(self):
return "{}-{}".format(self.name, self.get_created)
I have Profile user in database I do not understand:
Thanks for your help
As you are looking up on pk against User id which is not right as you don't have made the name field as primary_key=True or inherited from User model itself. You have to look up on name field of profile
profile = Profile.objects.get(name_id=user_id)
You can set name as primary key like this:
name = models.ForeignKey(User, on_delete=models.CASCADE, primary_key=True)
and then you can look up on pk:
profile = Profile.objects.get(pk=user_id)
I tried very hard to find out the problem, but I failed.
I am getting the following exception:
Error-NoneType object has no attribute 'membership_type'
I think that the problem is in context as if I use context as None then the error occurs.
I tried to use a foreign key to referring the Membership class and all the objects of it, but still get this error.
models.py
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
MEMBERSHIP_CHOICES = (
('Enterprise','ent'),
('Professional','pro'),
('Free','free')
)
class Membership(models.Model):
slug = models.SlugField()
membership_type =
models.CharField(choices=MEMBERSHIP_CHOICES,default='Free',max_length=30)
price = models.IntegerField(default=15)
stripe_plan_id = models.CharField(max_length=40)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user= models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=40)
membership = models.ForeignKey(Membership, on_delete=models.SET_NULL,
null=True)
def __str__(self):
return self.user.username
def post_save_usermembership_create(sender,instance, created, *args,
**kwargs):
if created:
UserMembership.objects.get_or_create(user= instance)
user_membership, created = UserMembership.objects.get_or_create(user=
instance)
if user_membership.stripe_customer_id is None or
user_membership.stripe_customer_id=='':
new_customer_id = stripe.Customer.create(email= instance.email)
user_membership.stripe_customer_id = new_customer_id['id']
user_membership.save()
post_save.connect(post_save_usermembership_create,
sender=settings.AUTH_USER_MODEL)
class Subscription(models.Model):
user_membership = models.ForeignKey(UserMembership,
on_delete=models.CASCADE)
stripe_subscription_id = models.CharField(max_length=40)
active = models.BooleanField(default=True)
def __str__(self):
return self.user_membership.user.username
courses/views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView,View
from .models import Course, Lesson
from membership_app.models import UserMembership
class CourseListView(ListView):
model = Course
class CourseDetailView(DetailView):
model = Course
class LessonDetailView(View):
def get(self, request, course_slug, lesson_slug, *args, **kwargs):
course_qs = Course.objects.filter(slug=course_slug)
if course_qs.exists():
course = course_qs.first()
lesson_qs = course.lessons.filter(slug=lesson_slug)
if lesson_qs.exists():
lesson = lesson_qs.first()
user_membership = UserMembership.objects.filter(user = request.user).first()
user_membership_type =
getattr(user_membership.membership,'membership_type',None)
# print(user_membership_type)
course_allowed_membership_type = course.allowed_membership.all()
context = {
'object': None
}
if course_allowed_membership_type.filter(membership_type=user_membership_type).exists():
context = {'object':lesson}
return render(request, "courses/lesson_detail.html",context)
templates
{% if object is not None %}
{{ object.title }}
{{ object.description }}
{% else %}
<h3>Upgrade Membership</h3>
{% endif %}
Your problem is in this line.
user_membership_type = user_membership.membership.membership_type
The reason is that you are allowing UserMembership.membership to be a null value. So when you retrieve a UserMembership with membership equal to None and then try to get membership_type off of that it raises an error. I think that getattr is your best solution to this problem.
user_membership_type = getattr(user_membership.membership, 'membership_type', None)
I want to show twitter data based on twitter username in my
template (Tweepy) but I don't know how to send data from my models into my views.
The content of models.py is:
<pre>
from django.db import models
from django.conf import settings
User = settings.AUTH_USER_MODEL
# Create your models here.
class Feed(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
feed = models.CharField(max_length=211, blank=True, null=True)
twitter = models.CharField(max_length=211, blank=True, null=True) # this is the twitter username which the user can enter and be sent to the views to api.get_user(twitter)
def __str__(self):
return self.feed
</pre>
The content of views.py is:
<pre>
from django.shortcuts import render
from django.views.generic import TemplateView
from .tweet import *
from .models import Feed
def feed(request):
api = tweepyapi(request)
user = api.get_user(twitter) # I want this portion to be dynamic.
findfriends = user.friends()
return render(request, 'feeds/feeds.html', {
'user': user,
'findfriends': findfriends
})
</pre>
let's say you have Profile model related to User model via one-to-one relation
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
twitter_username = models.CharField(max_length=40, blank=True)
def get_absolute_url(self):
context = {
'id':self.id,
}
return reverse("viewprofile", kwargs=context)
and in your template, we provide a link to user's profile as
{% for user in user_list %}
{{ user.get_full_name }}
{% endfor %}
now assuming you are passing id of user in get_absolute_url, your url will look like
url(r'^(?P<id>[0-9]+)/$', views.feed, name="viewprofile")
and then in your view
def feed(request,id):
profile = get_object_or_404(UserProfile,user__id=id )
api = tweepyapi(request)
user = api.get_user(profile.twitter_username)
findfriends = user.friends()
return render(request, 'feeds/feeds.html', {
'user': user,
'findfriends': findfriends
})
So I have created a a dynamic formset that allows the user to add or remove as many forms as they want. Now, I am trying to do custom validation in a field(block_name) in the forms.
It seems like it is working because if the user input doesn't match a certain regex, then the data will not be saved. The problem is that there is no message showing that the input is wrong.
Also, if the user inputs incorrect data and tries to submit the page will redirect to itself and erase all the input data. How can I make the page stay in the same view if the input is wrong and also show error messages?
forms.py:
import re
from django import forms
from django.forms.models import modelformset_factory
from inventory.models import Block
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
# Form for block requests
class BlockForm(forms.ModelForm):
block_name = forms.CharField(required=True, validators= [RegexValidator('^s\d{3}rf\d*b\d*e\d+r\d+w\d*[cgls][abcdex][ed][hv][sbaec][a-d] [a-d][0-7][apfg]a', message="Please enter valid block name", code="invalid_name")])
def __init__(self, *args, **kwargs):
super(BlockForm, self).__init__(*args, **kwargs)
self.empty_permitted = False
class Meta:
model = Block
fields = ['block_name', 'block_derivatives', 'block_subsystems', 'owners']
def clean_block_name(self):
print self.cleaned_data
block_name = self.cleaned_data.get('block_name')
if block_name == "a":
print ("block name is a")
raise forms.ValidationError(
('Please enter a block name'))
return block_name
models.py:
import datetime
import re
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
class Inventory(models.Model):
class Meta:
verbose_name_plural = "Inventories"
inventory_name = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published')
def __str__(self): # __unicode__ on Python 2
return self.inventory_name
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Block(models.Model):
class Meta:
verbose_name_plural = "Request Blocks"
inventory = models.ForeignKey(Inventory, null=True)
block_status = models.CharField(max_length=20, blank=False)
#617block_name = models.CharField(max_length=50, blank=False, null=False, validators=[block_nameTest])
block_name = models.CharField(max_length=50, blank=False, null=False)
block_derivatives = models.CharField(max_length=100)
block_subsystems = models.CharField(max_length=40)
owners = models.CharField(max_length=100)
def __str__(self):
return self.block_name
def block_owners(self):
return str(self.owners)
views.py:
from django.forms.models import modelformset_factory
from django.forms.formsets import formset_factory
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic
from django.http import HttpResponse
from django.shortcuts import render_to_response
from .models import Inventory, Block
from .forms import BlockForm
# Create your views here.
def requests(request, inventory_id):
BlockFormSet = formset_factory(BlockForm, extra=1)
inventory = get_object_or_404(Inventory, pk=inventory_id)
formset = BlockFormSet(request.POST)
if request.method == 'POST':
formset = BlockFormSet(request.POST)
if formset.is_valid():
for form in formset:
print form
form.save()
print "Success"
return HttpResponseRedirect('/inventory/2')
else:
print "Yo, this stuff is not validated"
else:
print "LOLOLOLOL"
return render(request, 'inventory/requests.html', {'inventory': inventory, 'formset': BlockFormSet})
requests.html:
{% block content %}
<div class="requestForm">
<form id="blockForm" class="original" action="{% url 'inventory:requests' inventory.id %}" method="post">{% csrf_token %}
<!-- Add New Row -->
{{formset.management_form}}
{% for form in formset %}
<div class='item'>
<ul>{{ form.as_table}}<ul>
<p style=""><a class="delete" href="#">Delete</a></p>
</div>
{% endfor %}
<p><a id="add" href="#">Add another item</a></p>
<input type="submit" name="submit" value="Request Blocks" id="submitButton">
</form>
</div>
{% endblock %}
You're redirecting after an invalid POST, rather than redisplaying the same form. Even though your redirect is to the same view, it loses the POST data and the form is therefore blank.
Drop the first else block, and let execution fall through to the final render line.
I'm trying to ask a user some additional info while signing up. I'm using django allauth for authorization and authentication. I try to add three more fields during the signup process. If If I run it, it shows me the standard form plus gender field. However, it doesn't seem to really work. How can I save the data? Could someone help? Thank you in advance!
EDITED: if I just use
if form.is_valid():
form.save()
return redirect('/success/')
I get an error:
save() missing 1 required positional argument: 'user'
I'm quite new to django.
I created signups app in the project.
I put this in allauth_settings.py:
ACCOUNT_SIGNUP_FORM_CLASS = 'signups.forms.MySignupForm'
My signups/model.py:
from django.contrib.auth.models import User
from django.db import models
from allauth.account.models import EmailAddress
from allauth.socialaccount.models import SocialAccount
import hashlib
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
about_me = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add= True, auto_now=False)
updated = models.DateTimeField(auto_now_add= False, auto_now=True)
GENDER_CHOICES = (
('m', 'Male'),
('f', 'Female'),
)
# gender can take only one of the GENDER_CHOICES options
gender = models.CharField(max_length=1, choices=GENDER_CHOICES,
verbose_name='Gender')
def __unicode__(self):
return self.user.username
class Meta:
db_table = 'user_profile'
def profile_image_url(self):
"""
Return the URL for the user's Facebook icon if the user is logged in via
Facebook, otherwise return the user's Gravatar URL
"""
fb_uid = SocialAccount.objects.filter(user_id=self.user.id, provider='facebook')
if len(fb_uid):
return "http://graph.facebook.com/{}/picture?width=40&height=40".format(fb_uid[0].uid)
return "http://www.gravatar.com/avatar/{}?s=40".format(hashlib.md5(self.user.email).hexdigest())
def account_verified(self):
"""
If the user is logged in and has verified hisser email address, return True,
otherwise return False
"""
if self.user.is_authenticated:
result = EmailAddress.objects.filter(email=self.user.email)
if len(result):
return result[0].verified
return False
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
my signups/forms.py:
from allauth.account.forms import SignupForm
from django import forms
from .models import UserProfile
class MySignupForm(SignupForm):
class Meta:
model = UserProfile
gender = forms.CharField(max_length=1, label='gender')
def save(self, user):
user.gender = self.cleaned_data['gender']
user.save()
my signups/views.py:
from django.template import RequestContext
from django.shortcuts import render_to_response
from .forms import SignupForm
def index(request):
form = MySignupForm(request.POST or None)
if form.is_valid:
???
return render_to_response("signups/index.html", locals(),
context_instance=RequestContext(request))
My index.html is very basic, I just wanted to see the representation of the form:
{% extends 'account/base.html' %}
{% block head_title %}ProjectName{% endblock %}
{% block content %}
<form method="POST" action="">
{{ form.as_p }}
<input type="submit">
</form>
{% endblock %}
You are instantiating the SignupForm, which is the standard form but not your MySignupForm in the view. Change it like this:
def index(request):
form = MySignupForm()
return render_to_response("signups/index.html", locals(),
context_instance=RequestContext(request))