A count of ForeignKey - python

I have class Team, which means a group of users. And the relation with User is One-to-Many.
class Team(models.Model):
member = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
But Team may consist of 2 and N members. I think to write manually is not our way, because it depends on count of people which is always variable.
class Team(models.Model):
member1 = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
member2 = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
member3 = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
How can I do it more elegant and rational? I mean to connect count variable and ForeignKeys associating with users.
upd 15:17 UTC. I still don't understand how to make this. Sorry. So, let's begin to draw.
For example, I wrote simple code
class Event(models.Model):
id_user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
But when I go to admin panel to add Event, I can add only one user. But I need to add a lot of users, who want to participate in the Event and then to divide them into Teams. I think I don't need another class Member. It seems unnecessary. Am I wrong?

As you stated Team model, have ManyToOne relation that means ForeignKey.
But Team may consist of 2 and N members.
You should create two models Team and Member. In Member model, you can store all information related to members such as their age, gender, city, etc.
In Team model, you can store information related to particular team which consists of more than one Member i.e. It has ManyToOne relation with Member.
Models.py:
from django.db import models
from django.contrib.auth.models import User
class Member(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
def __str__(self) -> str:
return f"{self.user.username}"
class Team(models.Model):
member = models.ForeignKey(Member, on_delete=models.SET_NULL, null=True)
Registering in admin site:
admin.py:
#admin.register(Member)
class MemberAdmin(admin.ModelAdmin):
list_display = ['id', 'user'] #Also specify other fields.
#admin.register(Team)
class TeamAdmin(admin.ModelAdmin):
list_display = ['id', 'member'] #Also specify other fields.
Edit:
According to the current picture, a Event can have more than one Team as well as more than one User. So, make two separate Foreign keys for both the models.
models.py
from django.db import models
from django.contrib.auth.models import User
class Team(models.Model):
# The below field is for name of team
name = models.CharField(max_length=200)
# The below field is for member of team.
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
def __str__(self) -> str:
return f"{self.name}"
class Event(models.Model):
# The below field is for name of event.
name = models.CharField(max_length=200)
# The below field is for user of event.
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
# The below is for team of event.
team = models.ForeignKey(Team, on_delete=models.SET_NULL, null=True)
def __str__(self) -> str:
return f"{self.name}"
admin.py
from django.contrib import admin
from .models import Team, Event
#admin.register(Event)
class EventAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'user', 'team']
#admin.register(Team)
class TeamAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'user']
views.py
from django.shortcuts import render
from .models import Team, Event
def home(request):
events = Event.objects.all()
return render(request, 'any_app_name/home.html', {'events': events})
home.html or template file:
<body>
<h2>All team information.</h2>
<div>
{% for event in events %}
<h3>{{forloop.counter}}</h3>
<p>Name of event: {{event.name}}</p>
<p>Name of user related to this event: {{event.user.username}}</p>
<p>Name of team related to this event: {{event.team.name}}</p>
<br><hr>
{% endfor %}
</div>
</body>

Create a team with one field team_name:
class Team(models.Model):
team_name = models.CharField(max_length=1000)
and assign users to this team:
class User(models.Model):
this_users_team = models.ForeignKey(Team, null=True, on_delete=models.SET_NULL)
in this case you can assign as many Users to any team, as you want

Related

Better way to fetch related object, in Self Refrencing ManyToMany Relationship?

I am working on a small application containing models CustomUser and PollQuestion. CustomUser having ManyToMany relation between itself and a CustomUser can have multiple PollsQuestion as well so there is Foreign Key relation between them.
An authenticated user is only able to see polls raised by users he is following, to full-fill this requirement i have written following view**:-**
Actually this is not view this is an utility method returning the polls to original view.
def all_polls_utils(request):
following = request.user.get_all_followings().values_list("id")
user_id = [id[0] for id in following]
all_polls = PollQuestion.objects.none()
for u_id in user_id:
user = CustomUser.objects.get(id=u_id)
polls = user.poll_questions.all()
all_polls = all_polls | polls
return all_polls
Main Question:- Is there in better way to do the same?
Any suggestion will be highly appretiated
I am posting the models bellow:-
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
email = models.EmailField(max_length=250, null=False)
name = models.CharField(max_length=50, null=False)
username = models.CharField(max_length=50, null=False, unique=True)
password = models.CharField(max_length=15, null=False)
user = models.ManyToManyField('self', through='Relationship', symmetrical=False, related_name='related_to')
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['name', 'email']
def get_all_polls(self):
pass
def create_relationship(self, person):
status, obj = Relationship.objects.get_or_create(
to_person=person,
from_person=self,
)
return status
def remove_relationship(self, person):
Relationship.objects.filter(
from_person=self,
to_person=person
).delete()
return 'dummy_value'
def get_all_followings(self):
return self.user.all()
class Relationship(models.Model):
from_person = models.ForeignKey(CustomUser, related_name='from_people', on_delete=models.CASCADE)
to_person = models.ForeignKey(CustomUser, related_name='to_person', on_delete=models.CASCADE)
And PollQuestion:-
class PollQuestion(models.Model):
user = models.ForeignKey(CustomUser, null=True, on_delete=models.CASCADE, related_name="poll_questions")
# Other fields
Note:- You can also suggest me a better title for this post?
Thanks in advance,
Hope to here from you soon.
Simply
def all_polls_utils(request):
all_polls_by_followed = PollQuestion.objects.filter(
user__in=request.user.get_all_followings()
)
As an aside, you should probably rename the user many-to-many in CustomUser to e.g. followed_users (with a related name followers).

Trying to implement Django Admin model validation

I am a beginner and trying to implement bid system in Django. I want it to work on both Django admin page and and template, therefore I created modelform and modeladmin in Admins.py.
models.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class category(models.Model):
category = models.CharField(max_length=50, default='SOME STRING')
def __str__(self):
return f"{self.category}"
class bid(models.Model):
listing = models.ForeignKey('listing', on_delete=models.CASCADE)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
bid = models.DecimalField(max_digits=6, null=True, decimal_places=2)
def __str__(self):
return f"{self.user}, {self.listing} {self.bid}"
class listing(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
Title = models.CharField(max_length=50)
Description = models.CharField(max_length=300)
Price = models.DecimalField(max_digits=6, null=True, decimal_places=2)
category = models.ForeignKey(category, on_delete=models.CASCADE, related_name="categories")
def __str__(self):
return f"{self.Title}"
admin.py
from django.contrib import admin
from .models import User, listing, category, bid
from django.core.exceptions import ValidationError
from django import forms
admin.site.register(User)
admin.site.register(listing)
admin.site.register(category)
class bidForm(forms.ModelForm):
class Meta:
model=bid
fields = ['user', 'listing', 'bid']
def clean(self):
start_price = self.cleaned_data.get('listing.Price')
userbid = self.cleaned_data.get('bid')
if userbid <= start_price:
raise ValidationError('Please place a bid higher than starting price')
return self.cleaned_data
class bidAdmin(admin.ModelAdmin):
form = bidForm
list_display = ('user', 'listing', 'bid')
admin.site.register(bid, bidAdmin)
It returns the following error:
'<=' not supported between instances of 'decimal.Decimal' and 'NoneType'.
Also I want to compare instances of previous and current bid on a listing to place a new bid, also modify any of previously placed bids even if it's lower than highest bid. but I have no idea how to code that. Please, help me...

Add username or any user authentication related field like first name, last name etc in model forms

I am creating a project in django in which I have two diff users i.e. Customers and restaurants.
I am creating a model for Menu in which I want add to add restaurant name in models directly(user name in this case) instead of taking input thorough forms every time.Also if possible if can take name from another field like this which is part of login system?
Models.py
class menu_details(models.Model):
restaurant_name = models.CharField(blank=True, max_length=20)
dish_name = models.CharField(blank=True, max_length=20)
dish_type = models.CharField(max_length=10, choices=food_type, default='veg')
price = models.CharField(blank=True, max_length=20)
description = models.TextField(blank=True, max_length=5000)
image = models.ImageField0(blank=True)
class Meta:
db_table = "menu_details"
If I understand well what you want, I think you need a Foreign Key Field pointing to the User infromation.
field_name= models.ForeignKey(User, help_text="", blank=True, null=True, on_delete=models.CASCADE)
Then you can access all the data from a user instance in views, for example:
this_menu = menu_details.objects.get(pk=1)
restaurant_name = this_menu.field_name.first_name
restaurant_email = this_menu.field_name.email
Or in templates:
{{ this_menu.field_name.first_name }}
{{ this_menu.field_name.email}}

Get Django admin.ModelAdmin to display join of two tables

I have a Django app with the following models.py
from django.db import models
class Order(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
delivered = models.BooleanField(default=False)
class OrderItem(models.Model):
order = models.ForeignKey(Order,
related_name='items',
on_delete=models.CASCADE)
product = models.ForeignKey(Product,
related_name='order_items',
on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
And in my admin.py, I have this
from django.contrib import admin
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ['id', 'first_name', 'last_name', 'email',
'paid', 'delivered']
list_filter = ['paid', 'delivered']
This only shows the Order table.
I would like to join the Order with the OrderItem table and display it in the Django admin. I am not sure this is relevant but for one Order, there could be many OrderItem(s).
As far as I know, you can't show OrderItems in OrderAdmin directly. But you can show Order in OrderItemAdmin, or use InLineModelAdmin to show OrderItems in Order Detail page. Like this:
class OrderItemInline(admin.TabularInline):
model = OrderItem
class OrderAdmin(admin.ModelAdmin):
inlines = [
OrderItemInline,
]
If you still want to display OrderItems (or parts of order item) in admin page, then you can add a method in list_display field, and use that method to fetch OrderItems. Like this:
class OrderAdmin(admin.ModelAdmin):
list_display = (..., 'get_order_items')
def get_order_items(self, obj):
return return ", ".join(obj.items.values_list("pk", flat=True))
get_order_items.short_description = 'Order Items'

How to join results of two models in Django?

I am trying to make a user panel in which each user's profile info (like avatar, joined date, etc.) are being displayed along with their posts. Here is the view that render the threads:
def topic(request, topic_id):
"""Listing of posts in a thread."""
posts = Post.objects.select_related('creator') \
.filter(topic=topic_id).order_by("created")
posts = mk_paginator(request, posts, DJANGO_SIMPLE_FORUM_REPLIES_PER_PAGE)
topic = Topic.objects.get(pk=topic_id)
topic.visits += 1
topic.save()
return render_to_response("myforum/topic.html", add_csrf(request, posts=posts, pk=topic_id,
topic=topic), context_instance=RequestContext(request))
The Topic model is:
class Topic(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(max_length=10000, null=True)
forum = models.ForeignKey(Forum)
created = models.DateTimeField()
creator = models.ForeignKey(User, blank=True, null=True)
visits = models.IntegerField(default = 0)
And the UserProfile model:
class UserProfile(models.Model):
username = models.OneToOneField(User)
name = models.CharField(max_length=30, blank=True)
city = models.CharField(max_length=30, blank=True)
country = models.CharField(
max_length=20, choices= COUTNRY_CHOICES, blank=True)
avatar = ImageWithThumbsField(), upload_to='images', sizes=((32,32),(150,150),(200,200)), blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, blank=True)
The problem is how best to join these two tables so that userprofile fields can be displayed in topic.html along with username?
Add them to context since you already have a database relation Users and Topics.
# add this to context
topic = Topic.objects.get(pk=topic_id)
creator = topic.creator.get().profile # This pulls the user object from creator field
context['creator'] = creator # Add to context
Now you can use the 'creator' context to pull fields
<h1>{{ creator.name }}</h1>
as for the avatar, if you have your media root set in settings you simply use an
<img src="/media/images/{{ creator.avatar }}">
Oh and also you can save alot of time by using ListView and DetailView part of Django's class based views.
Sorry forgot to mention you should add a related name to your one to one,
username = OneToOneField(User, related_name='profile')

Categories

Resources