Querying a User Profile model - django

I'm having trouble with this query.
Users application
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
current_story = models.PositiveSmallIntegerField(null=True)
return f'{self.user.username} Profile'
To avoid confusion, the 'current_story' will eventually be a foreign key for the Books.story model (excluded here) once I learn how to do use a foreign key across apps.
Books application
models.py
class character(models.Model):
fk_user = models.ForeignKey(User, default='1', on_delete=models.CASCADE)
fk_story = models.ForeignKey(story, default='1', on_delete=models.CASCADE)
name = models.CharField(max_length=100, default='', null=True)
def __str__(self):
return self.name
class Meta:
ordering = ('name', )
views.py
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from users.models import Profile
from .models import (character)
class listof_characters(LoginRequiredMixin, ListView):
model = character
template_name = '/list_characters.html'
context_object_name = 'characters'
ordering = ['name']
def get_queryset(self):
?
This is where i'm stuck. I need character.fk_story = User.profile.current_story.
I don't how to phrase this query, I've tried several different things based on other answers and I've tried User.current_story, User.userprofile.current_story as well.
I just need to filter the list of characters by current user's 'current_story' value.

Try to use this:
fk_story = Profile.objects.filter(owner=request.user).order_by('current_story')

Do what Lars said but use self.request.user instead of request.user
UPDATE
urls.py
urlpatterns = [
# other urls
path('characters/<int:pk>/', views.CharactersView.as_view(), name='characters'),
]
views.py
class CharactersView(LoginRequiredMixin, DetailView)
model = story
template_name = '/list_characters.html'
def get_queryset(self):
story = story.objects.get(pk=self.kwargs['pk']) # you need to pass a pk of the story you need the characters for in your url
characters = character.objects.filter(fk_story=story)
return characters
(here i replaced ListView with DetailView so we can query by the story model)
then in your template:
{% for character in characters %}
{{ character.name }}
{% endfor %}
P.S. Always start your Model names and ClassBasedViews with uppercase letters for better readability

def get_queryset(self):
profile = Profile.objects.get(user=self.request.user)
# or better use
# profile = get_object_or_404(Profile, user=self.request.user)
queryset = character.objects.filter(fk_story =profile.current_story)
return queryset
In order for this to work, you also need to change your Profile model.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
current_story = models.ForeignKey(story, on_delete=models.CASCADE)
return f'{self.user.username} Profile'
Note here I am jusing foreignkey rather than integerfield.

Related

making an API that adds instances to ManyToMany fields of a model in django rest framework

I am making a movie watching website in which there are users and films and the user model has a ManyToMany Field that references the film model. it's called WatchList and an authenticated user can add any movie they want to this watchlist.
My problem is that I want an API that only gets the ID of a film and adds it to the user's watch list.
these are my models and serializers and I am trying to make a view to implement this API.
# models.py
class Film(models.Model):
filmID = models.AutoField(primary_key=True)
title = models.CharField(max_length=150)
# ...
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
watchList = models.ManyToManyField(Film)
objects = UserManager()
USERNAME_FIELD = 'username'
# serializers.py
class WatchListSerializer(serializers.ModelSerializer):
class FilmSerializer(serializers.ModelSerializer):
model = Film
fields = ('filmID', 'title',)
read_only_fields = ('filmID', 'title')
film_set = FilmSerializer(read_only=True, many=True)
class Meta:
model = get_user_model()
fields = ('userID', 'film_set')
read_only_fields = ('userID',)
# views.py
class WatchListAddView(...):
pass
The serializer can be changed. but this kind of shows what I want the api to be. the authentication validation part is already taken care of, so imagine that any request to the view is from an authenticated user.
I would not recommend patching this directly and instead create a separate endpoint for adding removing data to this field.
In your case it would look like this. I show just a small working example, you can adjust it to your needs
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
#action(detail=True,
methods=['POST'])
def add_film_to_watch_list(self, request, **kwargs):
film = get_object_or_404(klass=Film, filmID=kwargs.get('filmID'))
user = self.get_object()
user.watchList.add(film)
return Response("Success")

How to save MultipleChoiceField to db

I want to create a settings page where a user can select multiple values of skills they have. It will have a main category and then subcategories. I need to save those into my database, so I can query them and show their selected skillset again.
I know how to create the MultipleChoiceField but not how to save them to the database. How would I go on about that?
Forms.py
from django import forms
class skills(forms.Form):
jobs = [
('Håndværker', (
('Gulv', 'Gulv'),
('Væg', 'Væg'),
)
),
('Murer', (
('Mur', 'Mur'),
('blabla', 'blabla'),
)
),
]
job = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
choices=jobs)
Views.py
from .forms import skills
def index(request):
if request.method == 'POST':
form = skills(request.POST)
if form.is_valid():
picked = form.cleaned_data.get('job')
# do something with your results
else:
form = skills
return render(request, 'settings/index.html', {"form":form})
It currently looks like this when the page loads which is good. Next step is just how I would save it to the database, so I can display this again with their previous chosen values.
Since you don't have any models setup yet, you can look into django-multiselectfield, which would store the selected choices "as a CharField of comma-separated values". Then you'd just need to pass those values from your form.
Alternatively you can look into PostgreSQL's Array field.
I would recommend you have a Jobs model and a Skills Model. Then have a skills field on the job model which will be a ManyToManyField to the Skills model. The form for this can then be autogenerated for you by Django as a ModelForm.
# Create your models here.
class Skill(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
def __str__(self):
return self.name
class Job(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=20, null=False, blank=False)
skills = models.ManyToManyField(Skill)
def __str__(self):
return self.name
You can then add them to the db as
skill1 = Skill.objects.create(name="Skill One")
skill2 = Skill.objects.create(name="Skill Two")
skill3 = Skill.objects.create(name="Skill Three")
skill4 = Skill.objects.create(name="Skill Four")
job1 = Job.objects.create(name="Job One")
job1.skills.add(skill1)
job1.skills.add(skill2)
job2 = Job.objects.create(name="Job Two")
job2.skills.add(skill3)
job2.skills.add(skill4)
Have a form to display
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ["name", "skills"]
You can cutomize the form or the template to your linking
in models.py just create the field with CharField
from django.db import models
class UserProfileInfo(models.Model):
Gender = models.CharField(max_length=10,default='')
in forms.py just create CHOICE like below
class UserProfileInfoForm(forms.ModelForm):
YESNO_CHOICES = (('male', 'male'), ('female', 'female'))
Gender = forms.ChoiceField(choices=YESNO_CHOICES)
class Meta():
model = UserProfileInfo
fields = ('Gender',)
in views.py import this form and display it.
or you can definitely go with
https://pypi.org/project/django-multiselectfield/

Django's DB API can't come back with all results

I'm trying to list all Characters from a User, but my code only return the first Character, can someone lend me a hand?
I'm using the User class from django.contrib.auth.models package.
models.py
class Character(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
views.py
def sheetList(request):
charL = get_list_or_404(Character, pk=request.user.id)
return render(request, 'sm/sheetList.html',{'charList': charL})
You're filtering on the primary key, which by definition is unique. I suspect you meant to filter on the user:
get_list_or_404(Character, user=request.user)

Try to join a OneToOne relationship in Django

I need some help doing a join using Django, which seems like it should be easy. I have looked at the documentation but it seems like it won't join for some reason.
I am trying to get in my view, the model.Photo and model.PhotoExtended with both joined and then displayed in the view. Currently I am just trying to get the model.Photo displayed but with a join which finds the request.user and filters it based on that.
They are in different apps.
models.py for model.Photo
class Photo(ImageModel):
title = models.CharField(_('title'),
max_length=60,
unique=True)
slug = models.SlugField(_('slug'),
unique=True,
help_text=_('A "slug" is a unique URL-friendly title for an object.'))
models.py for model.PhotoExtended
class PhotoExtended(models.Model):
Photo = models.OneToOneField(Photo, related_name='extended', help_text='Photo required', null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, help_text='User that uploaded the photo')
views.py
class PhotoExtendedUserView(ListView):
template_name = 'photo_user_list.html'
def get_queryset(self):
user = get_object_or_404(User, username=self.request.user)
return Photo.objects.filter(photoextended__user=user)
You set the related_name on Photo (which shouldn't be capitalized by the way) to extended so you need to filter like so:
class PhotoExtendedUserView(ListView):
template_name = 'photo_user_list.html'
def get_queryset(self):
user = get_object_or_404(User, username=self.request.user)
# 'extended' vs. 'photoextended'
return Photo.objects.filter(extended__user=user)

django - relations between models

i have two model which are Post and Profile. i am keepin blog datas which are title,body,owner,slug etc in Post. and keepin' user profile settings which are slogan,email,website etc. in Profile
in my index.html page i display user profile infos and post lists in same page. so ;
i need to connect these two models each other. when someone goes to 127.0.0.1/blog/username (with or without login) all the data which are belong to user named 'username' must be there.
here is my models.py:
class Profile(models.Model):
slogan = models.TextField(blank=True)
twitter = models.CharField(max_length = 100,blank=True)
web_site = models.CharField(max_length=100,blank=True)
email = models.CharField(max_length = 100,blank=True)
def __unicode__(self):
return self.slogan
class Post(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length = 100)
body = models.TextField()
bodyPreview = models.TextField() #preview için body alanı
titlePreview = models.CharField(max_length=100) # preview için title alanı
slug = AutoSlugField(populate_from='title' ,unique=True)
posted = models.DateField(auto_now_add=True)
isdraft = models.BooleanField(default=False)
def __unicode__(self):
return self.title
#permalink
def get_absolute_url(self):
return ('view_blog_post',None,{'postslug':self.slug})
and my index view :
def index(request,username):
post_list = Post.objects.filter(owner__username=username).filter(isdraft=False).order_by("-posted")
p_index = Paginator(post_list,3) #anasayfa için pagination.[her sayfada 3 post]
page = request.GET.get('page')
try:
indexPag = p_index.page(page)
except PageNotAnInteger:
indexPag = p_index.page(1)
except EmptyPage:
indexPag = p_index.page(p_index.num_pages)
## i need to get user's profile datas here. ??
return render_to_response('index.html',
{'post_list':post_list,'p_index':indexPag,'profile':query},
context_instance = RequestContext(request))
I think you should change your Profile model and add a OneToOne relationship to the User model(for more info see here):
class Profile(models.Model):
user = models.OneToOneField(User)
...
class Posts(models.Model):
author = models.ForeignKey(User)
...
and then in your views you can do:
user = get_object_or_404(User, username=username)
post_list = Post.objects.filter(author=user).filter(isdraft=False).order_by("-posted")
return render_to_response('index.html',
{'post_list': post_list, 'user': user, ...}, ...)
And then in your template you are able to access the user's profile.More here
e.g {{user.get_profile.slogan}}
In your view:
def index(request, username):
user = User.objects.get(username=username)
return render(request, 'index.html', {'user':user})
In your template:
{{ user.post_set }}
and You will receive list of posts of current user.
The most natural way to achieve that is to add a OneToOne relation between your Profile model and the django's User model.
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
# More fields
class Article(models.Model):
author = models.ForeignKey(User)
# More fields
This way, you can access the profile data through a User object. Would be something like this:
user = User.objecets.get(username=username)
profile = user.profile
More info about this, you can read the django model fields documentation here
and you can also see this cool answer about the diference between the ForeignKey with unique=True and the OneToOneField
I hope this helps