I'm trying to pass a User model as the parameter for a ForeignKey in my models.py file, but I am getting the error TypeError: int() argument must be a string or a number, not 'User'.
Here are my files, please tell me what I'm doing wrong:
models.py
from django.db import models
class Lesson(models.Model):
name = models.CharField(max_length=30)
author = models.ForeignKey('auth.User')
description = models.CharField(max_length=100)
yt_id = models.CharField(max_length=12)
upvotes = models.IntegerField()
downvotes = models.IntegerField()
category = models.ForeignKey('categories.Category')
views = models.IntegerField()
favorited = models.IntegerField()
def __unicode__(self):
return self.name
populate_db.py
from django.contrib.auth.models import User
from edu.lessons.models import Lesson
from edu.categories.models import Category
users = User.objects.all()
cat1 = Category(1, 'Mathematics', None, 0)
cat1.save()
categories = Category.objects.all()
lesson1 = Lesson(1, 'Introduction to Limits', users[0], 'Introduction to Limits', 'riXcZT2ICjA', 0, 0, categories[0], 0, 0)
lesson1.save() # Error occurs here
Using positional arguments here is very confusing and appears to be the cause.
I can reproduce your error by using positional arguments on a ForeignKey on one of my own models. Using kwargs solves the problem.
I'm not even interested in looking into why - I have never used confusing positional arguments to populate a model (seems like they would break ALL the time too with confusing messages if you ever modified your model)
Edit: or much worse, a silent error with input fields going to the wrong model fields over time.
You should use keyword arguments as well as simply the initialization it by using default field values.
class Lesson(models.Model):
name = models.CharField(max_length=30)
author = models.ForeignKey('auth.User')
description = models.CharField(max_length=100)
yt_id = models.CharField(max_length=12)
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
category = models.ForeignKey('categories.Category')
views = models.IntegerField(default=0)
favorited = models.IntegerField(default=0)
def __unicode__(self):
return self.name
lesson1 = Lesson(name='Introduction to Limits', author=users[0], description='Introduction to Limits', yt_id='riXcZT2ICjA', category=categories[0])
lesson1.save()
from django.contrib.auth import User (forgot exact import call)
author = models.ForeignKey(User)
Edit (additions): I would import the User the way that I stated and use 'author.category' for the other relationships. This has been resolved though by people who know more about Django than I do.
Related
I have problem with Django. I have class Typy and I want to name instances of this class based on username and field match_to_bet which is ModelChoiceField and is generated from base.
class Typy(models.Model):
users = (('user_1', 'user_1'),
('user_2', 'user_2'))
user = models.CharField(max_length=10, blank=True, choices=users)
mecz = models.ForeignKey('Mecz', on_delete=models.CASCADE, default=0)
choice = Mecz.objects.values()
match_to_bet = ModelChoiceField(queryset=choice, empty_label=None)
bet_home = models.BigIntegerField()
bet_away = models.BigIntegerField()
def __str__(self):
return str(self.user) + '_' + str(self.match_to_bet.__str__())
So far I get name with object's adress and have no idea how to change code to get names 'user'_'option chosen in match_to_bet'
current instances names
ModelChoiceField is used in Forms not in Models.
You want CharField or IntegerField with choice attribute.
Then you can do get_fieldname_display()
What is a better way of realizing rate field in model. Now I have this one:
class Story(models.Model):
...
rate = models.(help here)
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
Or there is another way of doing this?
As #Liudvikas Bajarunas said, it's enough to define story as a foreign key on the Rating model. You can access the story ratings using rating_set:
story_ratings = story.rating_set.all()
See the documentation on following relationships backwards for more info.
You can combine that approach with aggregation to get the average rating of a story:
class Story(models.Model):
...
#property
def average_rating(self):
return self.rating_set.all().aggregate(Avg('rate'))['rate__avg']
There are some improvements that you can make:
It is better to refer to the user model with the AUTH_USER_MODEL setting [Django-doc] to refer to the user model, since you can later change your mind about it;
You probably want to make user and story unique together, such that a user can not make two ratings for the same story;
some databases, like PostgreSQL allow us to enforce range constraints at the database level, and thus make it more safe.
we thus can rewrite this to:
from django.conf import settings
from django.db import models
from django.db.models import CheckConstraint, Q, UniqueConstraint
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Meta:
constraints = [
CheckConstraint(check=Q(rate__range=(0, 10)), name='valid_rate'),
UniqueConstraint(fields=['user', 'story'], name='rating_once')
]
You should either go with a through field like this:
class Story(models.Model):
rates = models.ManyToManyField(User, through=Rating)
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
or you can do it your way with a separate model which in this case your either should remove the rate field from Story model or remove the story field from Rating model:
class Story(models.Model):
...
# rate = models.(help here) No need anymore
class Rating(models.Model):
rate = models.FloatField(validators=[MinValueValidator(0.0), MaxValueValidator(10.0)])
story = models.ForeignKey(Story, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
and your queryset will be something like this:
story.rating_set.all()
Which will include all the ratings for the selected story instance.
I'm very confused about this right now,
so I know when there's a simple code like the below
def text_detail(request ,course_pk, step_pk):
step = get_object_or_404(Text, course_id = course_pk, pk=step_pk)
course_pk and step_pk from the url, and those requests are set equal to course_id and pk here. but what I don't understand is what is course_id and pk here? I mean, course_id is from Course model which is foreignkey to step. so it's self.Course.id so it's course_id. But then, how about the next one pk? shouldn't it be step_id = step_pk? when it's just pk how does django know which pk it is?
Sorry if the question is very confusing, I'm very confused right now.
Edit
class Step(models.Model):
title = models.CharField(max_length=200)
description = models.CharField()
order = models.IntegerField(default=0)
course = models.ForeignKey(Course)
class Meta:
abstract = True
ordering = ['order',]
def __str__(self):
self.title
class Text(Step):
content = models.TextField(blank=True, default="")
Actually the get_or_404() method doing a similar/exact job as below,
try:
return Text.object.get(pk=step_pk,course_id = course_pk)
except Text.DoesNotExist:
raise Http404
You can read the source code of the same here
What is course_id and pk ?
Both are attributes of your Text model, as the name indicates pk is your Primary Key of Text model and course_id is the id/pk of course field which is a FK.
EDIT
Text is inherited from Step model so, it will show properties of usual python class.Hence, the Text model be like this internally (not-exact)
class Text(models.Model):
content = models.TextField(blank=True, default="")
title = models.CharField(max_length=200)
description = models.CharField()
order = models.IntegerField(default=0)
course = models.ForeignKey(Course)
class Meta:
ordering = ['order', ]
def __str__(self):
return self.title
Example
text = Text.objects.get(id=1) # text instance with id=1
text.course_id # will hold the id of "course" instance which is related to the particular "text" instance
URL assignment and all those stuffs are entirely depends on your choice and logic. So If you need to get a Text instance in your view, do as below,
text = get_object_or_404(Text, pk = pk_of_TEXT_instance)
In my model I define a Thoughts and Comments model. One thought has many Comments as so:
class Thoughts(models.Model):
name = models.CharField(max_length=30)
thought = models.CharField(max_length=500)
class Comments(models.Model):
name = models.CharField(max_length=30)
comment = models.CharField(max_length=200)
original_post = models.ForeignKey(Thoughts, default=0)
On my site, when you go to view a thought, I want all of the comments to appear. It is my understanding that you can use choice_set to access attributes via one-to-many relationship. Here's my view:
def thought(request, thought_num):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
c = Comments.objects.create(name=form.cleaned_data['name'],
comment=form.cleaned_data['comment'])
c.save()
else:
form = CommentForm()
get_post = Thoughts.objects.get(pk=thought_num)
comments = get_post.choice_set.all()
return render(request, 'thought.html', {'form': form, 'comment':comments,})
In these lines, I attempt to access all comments related to a particular thought in order to print them in my template.
get_post = Thoughts.objects.get(pk=thought_num)
comments = get_post.choice_set.all()
When I access the page that should display the comments, I get this error:
Exception Type: AttributeError
Exception Value:'Thoughts' object has no attribute 'choice_set'
Perhaps I am missing something, I am not sure. I'm sure it's something simple. Thanks for your time
To retrieve all the Comments related to a Thought. You can do the following:
Thoughts.objects.get(pk=thought_num).comments_set.all()
If you would like to override the default related_name ("comments_set"). You can do the following:
original_post = models.ForeignKey(Thoughts, default=0, related_name='choice_set')
When you make a ForeignKey the default related name becomes the lower case name of the current class + "_set" so for your project should be:
get_post = Thoughts.objects.get(pk=thought_num)
comments = get_post.comments_set.all()
Or you could even create a custom related name instead of the default:
class Thoughts(models.Model):
name = models.CharField(max_length=30)
thought = models.CharField(max_length=500)
class Thoughts(models.Model):
name = models.CharField(max_length=30)
thought = models.CharField(max_length=500)
class Comments(models.Model):
name = models.CharField(max_length=30)
comment = models.CharField(max_length=200)
original_post = models.ForeignKey(Thoughts, default=0, related_name='comments')
so you can get your comments like this:
get_post = Thoughts.objects.get(pk=thought_num)
comments = get_post.comments.all()
I've been looking at the docs for search_fields in django admin in the attempt to allow searching of related fields.
So, here are some of my models.
# models.py
class Team(models.Model):
name = models.CharField(max_length=255)
class AgeGroup(models.Model):
group = models.CharField(max_length=255)
class Runner(models.Model):
"""
Model for the runner holding a course record.
"""
name = models.CharField(max_length=100)
agegroup = models.ForeignKey(AgeGroup)
team = models.ForeignKey(Team, blank=True, null=True)
class Result(models.Model):
"""
Model for the results of records.
"""
runner = models.ForeignKey(Runner)
year = models.IntegerField(_("Year"))
time = models.CharField(_("Time"), max_length=8)
class YearRecord(models.Model):
"""
Model for storing the course records of a year.
"""
result = models.ForeignKey(Result)
year = models.IntegerField()
What I'd like is for the YearRecord admin to be able to search for the team which a runner belongs to. However as soon as I attempt to add the Runner FK relationship to the search fields I get an error on searches; TypeError: Related Field got invalid lookup: icontains
So, here is the admin setup where I'd like to be able to search through the relationships. I'm sure this matches the docs, but am I misunderstanding something here? Can this be resolved & the result__runner be extended to the team field of the Runner model?
# admin.py
class YearRecordAdmin(admin.ModelAdmin):
model = YearRecord
list_display = ('result', 'get_agegroup', 'get_team', 'year')
search_fields = ['result__runner', 'year']
def get_team(self, obj):
return obj.result.runner.team
get_team.short_description = _("Team")
def get_agegroup(self, obj):
return obj.result.runner.agegroup
get_agegroup.short_description = _("Age group")
The documentation reads:
These fields should be some kind of text field, such as CharField or TextField.
so you should use 'result__runner__team__name'.