Update Table Relationship in Django Admin - python

I'm trying to create a directory of sites, I'm new in Django. What I need is: one site can have many payment processors and one payment processors (Paypal, Payza, etc) can belong to many sites. I'm trying to create a table relationship to represents this. My models are like this:
# Models.py
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
def __str__(self):
return self.name
class Sites_PaymentProcessors(models.Model):
site = models.ManyToMany(Sites)
payment_processor = models.ManyToMany(PaymentProcessors)
First, I'd like to know if my models are right. If not, how can I fix it?
Second, I'm using Django Admin site to create the sites and payment processors, how can I populate automatically my Sites_PaymentProcessors table with the relation between Sites and Payment_Processors when I add a new Site?

I would slightly change the models to accomodate ManyToManyFields like this:
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
sites = models.ManyToManyField('Sites', related_name='payment_processors')
def __str__(self):
return self.name
Now, if you want custom fields or store more information along with the relationship, you can make use of the through table
For example, if you want to associate the amount limit or something more custom:
class Sites(models.Model):
name = models.CharField(max_length=75)
link = models.CharField(max_length=150)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
class PaymentProcessors(models.Model):
name = models.CharField(max_length=75)
sites = models.ManyToManyField('Sites', related_name='payment_processors', through='SitePaymentProcessor')
def __str__(self):
return self.name
from django.core.validators import MaxValueValidator
class SitePaymentProcessor(models.Model):
site = models.ForeignKey('Site')
payment_processors = models.ForeignKey('PaymentProcessors')
amount_limit = models.IntegerField(default=1000,
validators=[
MaxValueValidator(100)
])
Now, again this is just an example.
Now, registering the admin classes would enable you to populate data into the models via the admin interface.
To auto-populate a large dataset, I would consider using fixtures rather than populating elements individually.

Related

Django: Defining 'present_company' from 'company_name' ManytoManyField

I have 2 models, Company and Employee, and defined company history as a ManytoManyField. I am trying to save the present company name of the employee which I get from the company name ManytoManyField. What should be the method to save it?
This is what I tried:
I tried to override the save method in Models.
models.py
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
def __str__(self) -> str:
return self.name
class Employee(models.Model):
name = models.CharField(max_length=100)
company_name = models.ManyToManyField(Company, blank=True)
present_company = models.CharField(max_length=100, blank=True)
def save(self):
super(Employee, self).save()
last_index = self.company_name.count()-1
self.present_company=str(Company.objects.filter(employee__name=self.name)[last_index])
super(Employee, self).save()
def __str__(self) -> str:
return self.name
I face two problems with this method:
I add/edit the models from the admin site, when I try to save the models and print the names of the company, it prints out the previous edit and not the latest one.
The order of the companies is not according to the order in which I save the models.
So, what could be the changes in this method, or, some other method to do this job.
As #Sahil mentions in comments that he wants the ordering based on employees joined the company.
when you use a Many-to-Many field Django in the backend created a separate table for mapping(through table). you can see this table in DB. now you want the details of Employee joined you can create a table(this table is just same as Many-to-Many field but with extra fields such as joined_in etc.) with details such as follow:
class EmployeeCompnyMap(models.Model):
employee = models.ForeignKey(
Employee, on_delete=models.CASCADE, related_name='employee_company_map')
company = models.ForeignKey(
Company, on_delete=models.CASCADE, related_name='company_employee_map')
is_active = models.BooleanField(default=True)
joined_on = models.DateField(auto_now_add=True)
resigned_on = models.DateField(blank=True, null=True)
Now if you want second_latest you can do the following in your save model:
last_company = self.employee_company_map.all().order_by('-resigned_on')[1]

DJANGO get objects in sql like join

Context: I'm forcing my self to learn django, I already wrote a small php based website, so I'm basically porting over the pages and functions to learn how django works.
I have 2 models
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Combo(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
dead = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
siteID = models.ForeignKey(Site, on_delete=models.PROTECT)
class Meta:
unique_together = ('username','siteID')
def __str__(self):
return f"{self.username}:{self.password}#{self.siteID.name}"
When creating a view, I want to get the Combo objects, but I want to sort them first by site name, then username.
I tried to create the view, but get errors about what fields I can order by Cannot resolve keyword 'Site' into field. Choices are: dead, id, password, siteID, siteID_id, timestamp, username
def current(request):
current = Combo.objects.filter(dead=False).order_by('Site__name','username')
return render(request, 'passwords/current.html',{'current':current})
Since I'm not necissarily entering the sites into the database in alphabetical order, ordering by siteID wouldn't be useful. Looking for some help to figure out how to return back the list of Combo objects ordered by the Site name object then the username.
You can order this by siteID__name:
def current(request):
current = Combo.objects.filter(dead=False).order_by('siteID__name','username')
return render(request, 'passwords/current.html',{'current':current})
since that is the name of the ForeignKey. But that being said, normally ForeignKeys are not given names that end with an ID, since Django already adds an _id suffix at the end for the database field.
Normally one uses:
class Combo(models.Model):
# …
site = models.ForeignKey(Site, on_delete=models.PROTECT)
if you want to give the database column a different name, you can specify that with the db_column=… parameter [Django-doc]:
class Combo(models.Model):
# …
site = models.ForeignKey(
Site,
on_delete=models.PROTECT,
db_column='siteID'
)

the model field's form disappears in django admin

I have two models, which are User and Record. Each has several fields.
from django.db import models
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,null=True)
def __str__(self):
return self.nickname
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
I register them in admin.py
from django.contrib import admin
from .models import User,Record
class RecordAdmin(admin.ModelAdmin):
list_display = ('expression','user','time')
class UserAdmin(admin.ModelAdmin):
empty_value_display = "空"
list_display = ('openid','nickname')
admin.site.register(User,UserAdmin)
admin.site.register(Record,RecordAdmin)
it works well in django admin initially. but one day, the fields of the Record model disppeared. It looks like
.
No field displays. It makes me unable to modify or add the values of the Record model. The other model User works well and all data exists in database. So why?
I think you just have to add on_delete=models.CASCADE in your ForeignKey Field. When you are using this kind of field, you have to specify the comportment when you make an update, a delete or anything else on this field.
So your script should be like this :
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
This is the result :
Edit :
You can also modify null=True by default=null
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,default=null)
def __str__(self):
return self.nickname

How to authenticate user for a specific object rather than whole class in django?

I am working on making an app to add clubs in website. This is my model.py file
from django.db import models
from stdimage import StdImageField
# Create your models here.
class Club(models.Model):
ClubName = models.CharField(max_length=200)
ClubLogo = StdImageField(upload_to='club_logo', variations={'thumbnail':(150, 200, True)})
ClubDetails = models.TextField()
ClubStartDate = models.DateField()
def __str__(self):
return self.ClubName
class Notice(models.Model):
NOTICE = 'NOTICE'
UPDATES = 'UPDATES'
EVENTS = 'EVENTS'
NOTICE_IN_CHOICES = (
(NOTICE, 'Notice'),
(UPDATES, 'Updates'),
(EVENTS, 'Events'),)
NoticeType = models.CharField(
max_length=20, choices=NOTICE_IN_CHOICES, default=NOTICE)
NoticeTag = models.CharField(max_length=30)
NoticeStartDate = models.DateField(auto_now_add=True)
NoticeEndDate = models.DateField()
NoticeFile = models.FileField(default='#', upload_to='notice/%Y/%m/%d')
NoticeContent = models.TextField(default='NA')
NoticeClub = models.ForeignKey(Club)
def __str__(self):
return self.NoticeTag
class Members(models.Model):
MemeberName = models.CharField(max_length=200)
MemberImage = StdImageField(upload_to='member_photo', variations={'thumbnail':(150, 120, True)})
MemberEmail = models.EmailField()
MemberClub = models.ForeignKey(Club)
def __str__(self):
return self.MemeberName
Now when i am making users via django's inbuilt admin panel i have option to give permission to users to change member of any club but i want to give access to change members of only that particular club which he is member of.
As you can see in this picture that all club are in dropdown option when someone who has access to add notices adding otices. But instead of that i want only one option in the dropdown for the useradmin to which he is associated.
this is my admin.py file
from django.contrib import admin
# Register your models here.
from club.models import Club, Members, Notice
admin.site.register(Club),
admin.site.register(Members),
admin.site.register(Notice),
This is a problem with which many users have been struggling with.
I have been using couple of external packages, and couple of self made solutions. But the best one I have found so far is Django Guardian It's an implementation of per object permission .This means you can manage users and permissions to which they have access to.

What is the proper way to structure models.py?

I'm trying to build the right models for my Django app. I'm trying to build something that will allow a user to save a URL into one (or more) playlist(s) that is tied to that user. Before I implement this, I want to make sure that this is the best way to structure my models.py.
class UserProfile(models.Model):
user = models.ForeignKey(User, primary_key=True) #what is the difference between ForeignKey and OneToOne? Which one should I use?
Playlist = models.CharField('Playlist', max_length = 2000) #1 user should be able to have multiple playlists and the default playlist should be "Favorites"
def __unicode__(self):
return self.User
class Videos(models.Model):
Video_url = models.URLField('Link to video', max_length = 200, null=True, blank=True)
Playlist = models.ManyToManyField(Playlist) #this should connect to the playlists a user has. A user should be able to save any video to any plalist, so perhaps this should be ManyToMany?
def __unicode__(self):
return self.Video_url
Woah. Firstly the question is probably too "localised" for SO. Anyway. I'd do it like this:
class PlayList(models.Model):
playlist = models.CharField(max_length=2000)
class UserProfile(models.Model):
# do you want each `User` to only have one `UserProfile`? If so then OneToOne
# primary keys are automatically formed by django
# how django handles profiles: https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
user = models.ForeignKey(User)
def __unicode__(self):
return self.User
class UserPlayList(models.Model):
# don't capitalise attributes, if you haven't seen PEP8 before, do now: http://www.python.org/dev/peps/pep-0008/
profile = models.ForeignKey(User)
playlist = models.ForeignKey(PlayList)
class Video(models.Model):
video_url = models.URLField(max_length=200, null=True, blank=True, help_text="Link to video")
def __unicode__(self):
return self.video_url
class VideoPlayList(models.Model):
video = models.ForeignKey(Video)
play_list = models.ForeignKey(UserPlayList)

Categories