Django beginner here.
I am trying to make a an app for where users can make connections, post stuff, chat, etc. There are two user types - Parents and Child. For this I extended the AbstractBaseUser model and created two another models - Parent and Child with a OneToOne link to the User.
#accounts/models.py
class User(AbstractBaseUser, PermissionsMixin):
REQUIRED_FIELDS = []
EMAIL_FIELD = "email"
USERNAME_FIELD = 'email'
objects = UserManager()
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=DefaultModel.MAX_LENGTH, unique=False)
last_name = models.CharField(max_length=DefaultModel.MAX_LENGTH, unique=False)
profile_photo = models.ImageField(default='uploads/profile/default_profile.jpg', upload_to=content_image_name)
cover_photo = models.ImageField(default='uploads/profile/default_cover.jpg', upload_to=content_image_name)
username = AutoSlugField(populate_from='first_name', unique=True, sep='.')
bio = models.CharField(max_length=255, blank=True, default="Nothing to see here !")
is_child = models.BooleanField(default=False)
is_parent = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
# storing timestamps for users.
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
CHOICES = (('M','Male'),('F','Female'),('O','Other'))
gender = models.CharField(max_length=10, choices=CHOICES)
def get_absolute_url(self):
return "/users/{}".format(self.username)
def __str__(self):
return "{} {}".format(self.first_name, self.last_name)
class Child(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
friends = models.ManyToManyField('self',
blank=True,
related_name='friends',
db_column='friends',)
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
class Parent(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
connections = models.ManyToManyField('self',
blank=True,
related_name='connections',
db_column='connections',)
def __str__(self):
return "{} {}".format(self.user.first_name, self.user.last_name)
As you can see a Child can only be a friend with another Child and a Parent can only connect with a Parent.
Basically I have two apps - Feeds for handling posts and accounts for handling accounts. There is a page for displaying the current users (/childs/ for Child and /parents/ for Parent) and another for friends (/friends/ for Child and /connections/ for Parent).
In the homepage (/home) of the apps there are two sidebars - one for showing users whom the request.user can send friend request to and another for displaying the friends of request.user. Since there is a single url (/home) for both user types, therefore the strategy is :
Make a base ListView for displaying both current users and friends.
Inherit it for the individual users and friends page.
Inherit it for home.html for /home.
#method_decorator(login_required, name='dispatch')
class UserList(ListView):
model = User
def get_context_data(self, *args, **kwargs):
context = super(UserList, self).get_context_data(**kwargs)
if self.request.user.is_child:
childs = Child.objects.exclude(user=self.request.user.child)
sent_requests = ChildFriendRequest.objects.filter(from_user=self.request.user.child)
recv_requests = ChildFriendRequest.objects.filter(to_user=self.request.user.child)
friends = self.request.user.child.friends.all()
recv_from = [i.from_user for i in recv_requests]
users = [i for i in childs if i not in friends and i not in recv_from]
sent_to = [ i.to_user for i in sent_requests]
context['users'] = users
context['sent'] = sent_to
context['friends'] = friends
context['recv_requests'] = recv_requests
elif self.request.user.is_parent:
parents = Parent.objects.exclude(user=self.request.user.parent)
sent_requests = ParentConnectionRequest.objects.filter(from_user=self.request.user.parent)
recv_requests = ParentConnectionRequest.objects.filter(to_user=self.request.user.parent)
connections = self.request.user.parent.connections.all()
recv_from = [i.from_user for i in recv_requests]
users = [i for i in parents if i not in connections and i not in recv_from]
sent_to = [ i.to_user for i in sent_requests]
context['users'] = users
context['sent'] = sent_to
context['connections'] = connections
context['recv_requests'] = recv_requests
return context
class ChildList(UserList):
template_name = "account/child/childs_list.html"
class FriendList(UserList):
template_name = "account/child/friend_list.html"
class ParentList(UserList):
template_name = "account/parent/parent_list.html"
class ConnectionList(UserList):
template_name = "account/parent/connection_list.html"
class Sidebar(UserList):
template_name = "feeds/home.html"
Now views of Feeds app also use home.html for it displaying feeds.
class PostListView(ListView):
model = Post
template_name = 'feeds/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated:
liked = [i for i in Post.objects.all() if Like.objects.filter(user = self.request.user, post=i)]
context['liked_post'] = liked
return context
The problem here is that whenever /friends or /childs is accessed I can see the users but in the /home no user is shown although I can see the posts.
Here's home.html
{% extends "feeds/layout.html" %}
{% load static %}
{% block friends_sidebar %}
<div class="widget stick-widget">
<h4 class="widget-title">People Nearby</h4>
<ul class="followers">
{% if users %}
{% for user_p in users %}
<li>
<figure>
<img src="{{ user_p.user.profile_photo.url }}" width="40" height="40" alt="">
</figure>
<div class="friend-meta">
<h4>{{ user_p.user }}</h4>
{% if not user_p in sent %}
Add Friend
{% else %}
Cancel Request
{% endif %}
</div>
</li>
{% endfor %}
{% else %}
<p>No one is here !</p>
{% endif %}
</ul>
</div>
{% endblock %}
I can only see :
No one is here !
So the question is how can I go working around this ? Is it because two views are using the same template ?
I am using Django 3.2.9 and Python 3.8.
As #Razenstein mentioned I needed to have the contexts of UserList in PostListView, so I inherited UserList in PostListView and that did it. Here's what was to be done :
class PostListView(UserListView):
model = Post
template_name = 'feeds/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 10
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated:
liked = [i for i in Post.objects.all() if Like.objects.filter(user = self.request.user, post=i)]
context['liked_post'] = liked
return context
The key here is to inherit the UserList class and use super() in get_context_data().
Related
models.py
here is my model
class Load_post(models.Model):
user = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False , blank=False , unique=True)
receiver_name = models.CharField(max_length=150)
sending_item = models.CharField(max_length=150)
weight = models.CharField(max_length=150)
metric_unit = models.CharField(max_length=30, default='SOME STRING')
quantity = models.PositiveIntegerField(default=1)
requested_shiiping_price = models.PositiveIntegerField()
pick_up_time = models.DateField()
drop_time = models.DateField()
paid_by = models.CharField(max_length=150)
created_at = models.DateTimeField(auto_now=True)
published_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def publish(self):
self.published_date = timezone.now()
self.save()
def get_absolute_url(self):
return reverse('local')
class Meta:
ordering = ["-created_at"]
unique_together = ["sender_name", "receiver_name"]
please check the phone number
forms.py
this is form.py
class Loader_post_form(forms.ModelForm):
phone_number = PhoneNumberField()
metric_unit = forms.ChoiceField(choices=UNIT, required=True)
class Meta:
model = Load_post
fields = ("pick_up_station", "destination_station",
"sender_name", "phone_number", "receiver_name",
"sending_item","image_of_load","weight","metric_unit",
"quantity","requested_shiiping_price","pick_up_time",
"drop_time","paid_by")
views.py
This is my views.py
absolute URL used in models already
class Loader_post_view(CreateView, LoginRequiredMixin):
login_url = 'Driver/login/'
form_class = forms.Loader_post_form
model = Loader_Signup
template_name = "Driver/post.html"
def form_valid(self,form):
form.instance.user = self.request.user
form.save()
return super(Loader_post_view,self).form_valid(form)
post.html
this is html page (template)
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
{% endblock content %}
this is html code
how to add it to the database
and I cannot see any error in my forms
thank you
am working on driver and client-side project
From what I see you html template cannot submit the form because you ae missing the <form> tags - if you do not have them hidden in your base.html.
Your html template should be something like this:
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
<form method="POST">
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
</form>
{% endblock content %}
The {{ form }} renders the form with all the inputs but does not create the tags needed for html forms.
In addition there are some other errors in the code you posted.
In your view the model you defined is called Loader_Signup, however the model you posted is Load_post. Either you posted the wrong model or you declared the wrong model in your view.
In your form one field is called image_of_load, however, this field is not part of you model.
In your model you have got a field called phone_number, you are defining a field with the same name in your form. The field in your form has got no connection to your model so take it out.
Unfortunately you are not providing any details about your PhoneNumberField so this cannot be checked.
I have django project with three below models:
models.py
from django.db import models
from django.contrib.auth.models import User
class Album(models.Model):
owner = models.ForeignKey(User)
title = models.CharField(max_length=127)
artist = models.CharField(max_length=63)
release_date = models.DateField()
logo = models.ImageField(blank=True, upload_to='album_logos', default='album_logos/no-image.jpeg')
t_added = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(null=True, blank=True, max_length=63)
class Meta:
ordering = ['-release_date']
def __str__(self):
return self.title
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
# is_favorite = models.BooleanField(default=False)
favorites = models.IntegerField(default=0)
song_file = models.FileField(blank=True, null=True, upload_to='song_files', default='song_files/mektub.mp3')
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Favorite(models.Model):
user = models.ForeignKey(User)
song = models.ForeignKey(Song)
created = models.DateTimeField(auto_now_add=True)
As you can see from these models many users can favorite many songs. In template, I want to add class to songs which are favorited by authenticated user:
template
<span {% if authenticated user favorited this song %}class="favorited" {% endif %}></span>
My problem is, I don't know how to write "if authenticated user favorited this song" in template. In terminal, I can get this information by this code:
user_favorited_this = song.favorite_set.filter(user=sample_user) and True or False
I couldn't do the same thing in template, since it doesn't support passing argument to filter method. How can I overcome this problem?
A tag filter can do what you want:
If the User.favorite_set.all has something in common with Song.favorite_set.all this means the current user has favorited that song
from django import template
register = template.Library()
# Method 1 for django queryset (Better)
#register.filter
def intersection(queryset1,queryset2):
return queryset1 & queryset2
# Method 2 for queryset or python List
#register.filter
def intersection(queryset1,queryset2):
return list(set.intersection(set(queryset1),set(queryset2)))
html:
{% if request.user.favorite_set.all|intersection:song.favorite_set.all %} class="favorited" {% endif %}
It may just be simpler to do this in the view, and then pass the result to the template as a boolean flag.
For example:
def song_view(request):
...
song = Song.objects.get(pk=request.GET['song_id'])
is_favorite = song.favorite_set.filter(user=request.user).exists()
return render(request, 'my_template.html', {'is_favorite': is_favorite})
or for a generic class based view:
class SongDetail(DetailView):
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
song = self.get_object()
is_favorite = song.favorite_set.filter(user=self.request.user).exists()
context['is_favorite'] = is_favorite
return context
and then the code in your template can be simplified to:
<span {% if is_favorite %}class="favorited" {% endif %}></span>
My problem is that I can not save the form. I think the problem lies in the event field in the Register model.
I do not want the user to choose an Event from the list, I want it to happen automatically, hence the code: form.cleaned_data['event'] = kwargs['pk']
This part of code kwargs['pk'] is from url.
Please any hint if this is good approch to dealing with forms and hint to solve my problem. Below is my code.
Thanks :)
Models:
class Event(models.Model):
title = models.CharField(max_length=500)
date = models.DateField()
text = models.TextField()
image = FilerImageField(null=True, blank=True)
flag = models.ForeignKey(Flag)
free_places = models.IntegerField()
class Meta:
ordering = ['-date']
def __str__(self):
return self.title
#property
def slug(self):
return slugify(self.title)
def get_absolute_url(self):
return reverse('events:detail', args=[self.slug, self.id])
class Register(models.Model):
event = models.ForeignKey(Event)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.CharField(max_length=30, blank=True)
street = models.CharField(max_length=50, blank=True)
post_code = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
email = models.EmailField()
phone_number = models.IntegerField()
def __str__(self):
return self.first_name
def get_event_name(self):
return self.event
View:
class EventDetailView(DetailView, ModelFormMixin):
model = models.Event
form_class = forms.RegisterForm
def get_success_url(self):
return reverse('events:list')
def post(self, request, *args, **kwargs):
form = self.get_form()
print(kwargs['pk'])
print(self.form_class)
if form.is_valid():
print(form.cleaned_data['event'])
form.cleaned_data['event'] = kwargs['pk']
form.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
My form:
class RegisterForm(ModelForm):
class Meta:
model = models.Register
fields = ('event', 'first_name', 'last_name', 'company', 'street', 'post_code', 'city', 'email', 'phone_number',)
My template:
{% extends 'base.html' %}
{% block content %}
<ul>
<h1>Detail page:</h1>
<li>{{ object.title }}</li>
<li>{{ object.text }}</li>
<li>{{ object.date }}</li>
</ul>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
What you are doing here is to insert into a validated data. Instead of that,
Initialize the form with request POST data which should include "event" key and its value you got from kwargs['pk']. Then validate it and save. You will not get validation errors, as well as the value will be saved.
Basically, even the event id you get from the url that has to be validated. Django does with db level check against the pk value you passed when you call is_valid.
I am trying to display the data in details template that I would obtain using AgentForm and I am also trying to add a Matrix1Form that will be unique to each agent, and that matrix1form would be displayed in details.html.
Here is my views.py and if I try to display the Matrix1Form, the data from Agent model doesn't get displayed and vice versa, if I want to display an agent, I have to comment out the Matrix1Form. There are no errors popping up so far. The data just don't get displayed.
views.py
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get(self, request, *args, **kwargs):
matrix1form = Matrix1Form()
return render(request, self.template_name, {'matrix1form':
matrix1form})
forms.py
class AgentForm(forms.ModelForm):
prefix = 'agentform'
class Meta:
model = Agent
fields = '__all__'
class Matrix1Form(forms.ModelForm):
prefix = 'matrix1form'
class Meta:
model = Matrix1
fields = '__all__'
models.py
class Agent(models.Model):
AgencyName = models.CharField(blank=True, max_length = 50,
verbose_name="Agency Name")
OtherAgencyName = models.CharField(max_length=50, blank=True)
FirstName = models.CharField(max_length=50, null=True)
LastName = models.CharField(max_length=50, null=True)
details.html
<ul>
<li>AgencyName: {{agent.AgencyName}} </li>
<li>OtherAgencyName: {{agent.OtherAgencyName}} </li>
<li>First Name: {{agent.FirstName}} </li>
<li>Last Name: {{agent.LastName}} </li>
</ul>
<form class="form-horizontal" action="" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ matrix1form.as_table }}
</table>
</form>
if i understand you correct, you need to override get_context_data for example:
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get_context_data(self, **kwargs):
# ^^^^^^^^^^^^^^
context = super(AgentDetailsView, self).get_context_data(**kwargs)
matrix1form = Matrix1Form()
context['matrix1form'] = matrix1form
return context
The problem i am having is I can't access a model's fields in the html {{ profile.slug }}. In the template I can access the model, let me show you.
I have 2 models Profile, and Oferto.
In Detail view on the Oferto Model, I want to link to the user's profile who created the Oferto.
the Oferto Model has a field user,
I am trying to lookup the profile.slug that coresponds to the Oferto.user
The following is seen in the browser from a test
[<Profile: Red>]
Name: oFFER
User: Red
Description:
Time: 9
Stelo: None
Requirements:9
and the template is as follows
{% block content %}
<a>{{ profile }}</a>
<p>Name: {{ oferto.name }}</p>
<p>User: {{ oferto.user }}</p>
<p>Description: {{ oferto.descripion }}</p>
<p>Time: {{ oferto.time }}</p>
<p>Stelo: {{ oferto.stelo }}</p>
<p>Requirements:{{ oferto.requirements }}</p>
<hr>
<p>Location: {{ oferto.location }}</p>
<p>tags: {{ oferto.tags }}</p>
<p>{{ PROJECT_URL }} / {{ STATIC_URL }}{{ oferto.image }}</p>
{% endblock %}
if i try to use profile.slug it just comes up blank and is not in the html
views.py
class OfertoDetailView(ExtraContextMixin,DetailView):
model = Oferto
def extra(self):
profile = Profile.objects.all()
return dict(profile = profile)
class ExtraContextMixin(object):
def get_context_data(self, **kwargs):
context = super(ExtraContextMixin, self).get_context_data(**kwargs)
context.update(self.extra())
return context
def extra(self):
return dict()
if your wondering why I am using a mixin see an answer from
django - DetailView how to display two models at same time
My Models
# Ofertoj.models.py
class Oferto(models.Model):
user = models.ForeignKey(User)
# profile = models.OneToOneField(Profile)
name = models.CharField(max_length=150)
description = models.TextField(max_length=3000)
time = models.DecimalField(max_digits= 10000000,decimal_places =2,null= True)
stelo = models.DecimalField(max_digits= 10000000,decimal_places =2,null= True)
location = models.TextField(max_length=3000)
slug = AutoSlugField(('slug'), max_length=128, unique=True, populate_from=('name',))
tags = tagging.fields.TagField()
image = models.ImageField(upload_to='Ofertoj',blank=True, null=True)
requirements = models.TextField(max_length=550000,blank=True, null=True)
def get_absolute_url(self):
return reverse('oferto_detail', kwargs={'slug': self.slug})
def __unicode__(self):
return self.name
def get_tags(self):
return Tag.objects.get_for_object(self)
# turtle.models.py
class BaseInfo(models.Model):
name = models.CharField(max_length=100)
contact_name = models.CharField(max_length=100)
email = models.EmailField(max_length=75)
phone = models.CharField(max_length=20)
address = models.CharField(max_length=3000)
city = models.CharField(max_length=3000)
state = models.CharField(max_length=3000)
code = models.IntegerField()
country = models.CharField(max_length=3000)
image = models.ImageField(upload_to='photos/%Y/%m/%d',blank=True)
slug = AutoSlugField(('slug'), max_length=128, unique=True, populate_from=('name',))
tags = tagging.fields.TagField()
def __unicode__(self):
return self.name
def get_tags(self):
return Tag.objects.get_for_object(self)
# profile.models.py
class Profile(BaseInfo):
bio = models.TextField(max_length=15000000)
user = models.ForeignKey(User)
def get_absolute_url(self):
return reverse('profile_detail', kwargs={'slug': self.slug})
# tempilo.profiles.UserProfiles
from models import Profile
class MyUser(AbstractBaseUser):
identifier = models.CharField(max_length=40, unique=True)
USERNAME_FIELD = 'identifier'
profile = OneToOneField(Profile,primary_key=True)
profile is a queryset, not an instance. Querysets don't have a slug attribute.
You either need to get a specific instance of Profile in your extra method, or iterate through the profiles in your template.
The fact that [<Profile: Red>] is visible in the test output indicates that you are passing Profile instance to the template correctly.
Therefore the problem lies within profile.slug. Are you sure that you have slug field on your Profile class?