Foreign key in django signals - django

i need use node in created method signals, but raise this error
my signals :
#receiver(post_save, sender=AUTH_USER_MODEL)
def create_user_progress(sender, instance, created, **kwargs):
specialties = instance.specialties
section = SectionSpecialties.objects.filter(specialties=specialties)
section_slice = section.values_list('section_id', flat=True)
node = Nodes.objects.filter(sections__in=section_slice)
if created:
Progress.objects.create(user=instance, node=node)
my error :
Cannot assign "<QuerySet [<Nodes: dsdsd - cccc>, <Nodes: chizi nemiyare - cccc>]>": "Progress.node" must be a "Nodes" instance.
my model :
class Progress(core_models.TimeStampedModel):
node = models.ForeignKey(section_model.Nodes, related_name='mentor_user', on_delete=models.CASCADE, null=True)
mentor = models.ForeignKey(mentor_user.MentorUser, related_name='mentor_user', on_delete=models.CASCADE, null=True)
user = models.OneToOneField(User, related_name='mentor_user', on_delete=models.CASCADE)

Related

How to override "Cannot asign must be an instance" in Django?

I have two models:
class Message(models.Model):
username = models.CharField(max_length=255)
room = models.CharField(max_length=255)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Notification(models.Model):
notification_author = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="notifauthor")
notification_from = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="notiffrom")
is_read = models.BooleanField(default=False)
signals:
#receiver(post_save, sender=Message)
def create_user_notification(sender, instance, created, **kwargs):
if created:
Notification.objects.create(
notification_author=instance.username,
notification_from=instance.room)
#receiver(post_save, sender=Message)
def save_user_notification(sender, instance, **kwargs):
instance.username.save()
I am trying to create signal for creating notification after message is created. But have error:
Cannot assign "20": "Notification.notification_author" must be a "Profile" instance.
How to override it (if possible) without changing CharField to FK in Message model?
Found smth about eval(), but it does not still work
The question is how to convert the string to Profile model without
using FK
notification_author=Profile.objects.get_or_create(username=instance.username)

OnetoMany field in django models

From my search it comes to my understanding there is no OnetoMany Field in django, can someone explain or simplify a solution if i wanted to have these three classes connected to each other.
a UserRank class which i can define as many as ranks i want,example (captain,2nd eng,chief mate...etc)
a User class which can have one of the above ranks,
a job class which can have 1 or many ranks from the UserRank class
models.py
class UserRank(models.Model):
rank = models.CharField(blank=True,null=True,max_length=150)
def __str__(self):
return self.rank
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=150,unique=True)
name = models.CharField(max_length=150,)
phone = models.CharField(max_length=50)
date_of_birth = models.DateField(blank=True, null=True)
picture = models.ImageField(blank=True, null=True, upload_to='users_imgs')
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
last_login = models.DateTimeField(null=True)
user_rank = models.ForeignKey(UserRank,related_name='userRank',null=True,on_delete=models.SET_NULL)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email','name']
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username.split()[0]
class Job(models.Model):
job_type = (
('I', 'Interval'),
('O', 'One time'),
)
name = models.CharField(max_length=100)
description = models.CharField(max_length=100)
type = models.CharField(max_length=1, choices=job_type)
interval = models.IntegerField()
is_critical = models.BooleanField()
due_date = models.DateField()
user_rank = models.ManyToManyField(UserRank,related_name='ranks',blank=True)
component = models.ForeignKey(
Component, related_name='jobs', on_delete=models.CASCADE)
runninghours = models.ForeignKey(
RunningHours, related_name="RHjobs", on_delete=models.CASCADE)
def __str__(self):
return self.name
You are probably looking for the "reverse relation" of a ForeignKey relation. Look at the Django documentation: Following relationships backwards
(Summary: Entry has a foreign key to Blog, and by default Blog.entry_set is a manager for related Entry objects, f.ex. Blog.entry_set.all() or any more complex Queryset to filter them. THe name entry_set is a default, you can change it via related_name on the ForeignKey in Entry)
In a one-to-many relationship, the "child" instance contains the primary key of the parent instance as a foreign key.
This means that if you have a relationship between UserRank and Job, each Job instance will have an attribute of type ForeignKey containing the primary key of the parent Job instance.
# Setup
class UserRank(models.Model):
...attributes
class Job(models.Model):
user_rank = models.ForeignKey(UserRank, on_delete=models.CASCADE, related_name="jobs")
# Accessing jobs from UserRank
user_rank_1 = UserRank.objects.create(...)
# There is one UserRank instance with many child job instances, so we have to cycle through them
for job in user_rank_1.jobs.all():
print(job)
# Result
# >>> job1
# >>> job2
# >>> job3
# Accessing UserRank from a Job instance
job = Job.objects.get(id=1)
# Every job instance only has one parent UserRank, so it's sufficient to reference it directly with the dot notation
print(job.user_rank)
# Result
# >>> user_rank_1

django checkbox select multiple models

Hi I have the following django model:
class Issue(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField(auto_now=True)
assignee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='assignee')
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner', null=True, blank=True)
description = models.TextField()
state = models.IntegerField(choices=STATUS_CHOICES, default=1)
priority = models.IntegerField(choices=RELEVANCE_CHOICES, default=2)
expired_date = models.DateField(auto_now=False, null=True, blank=True)
and a form which allow a user to create an Issue instance:
class IssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ('title', 'description', 'assignee', 'state', 'priority', 'expired_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].label = "Titolo"
self.fields['description'].label = "Descrizione"
self.fields['state'].label = "Stato"
self.fields['priority'].label = "Priorità"
self.fields['expired_date'].label = "Termine"
self.fields['expired_date'].widget.attrs.update({'class': 'datepicker'})
self.fields['assignee'] = forms.MultipleChoiceField(
choices=self.fields['assignee'].choices,
widget=forms.CheckboxSelectMultiple,
label=("Assegnatario")
)
def clean(self):
cleaned_data = super().clean()
user_id = [i for i in cleaned_data['assignee']]
cleaned_data['assignee'] = [User.objects.get(id=i) for i in user_id]
return cleaned_data
I render this form and the field assignee is a checkbox.
I would like to be able to choose several assignee for the same issue, but I got an error because the Issue model expect just one User instance
How can I modify my model Issue in order to get more than one user ?
Thanks
you can create a new class and name it Issue_Instance where every Issue Object can have an assignee as a foreign key the problem that the relation is one to many because you have to choose more than one assignee and Django doesn't support the idea of having Array or List of Foreign Keys(I don't know any frame works that do :=) ) so I would suggest creating a new class or make the foreign key relation one-to-many key field read about it it will be very useful to solve your problem

Modelserializer using kwargs to get FK object

I'm creating a Django (1.8) webapp that saves racing laptimes and scoreboards. The database is populated using an API built using Django Rest Framework. It's the first time I'm trying to build a proper api using rest framework.
A quick overview of the models:
Event, A racing event/weekend
Session, A single race/practice/quali - FK Event
Car, A car taking part in a session - FK Session
Lap, Laps for specific car - FK Car
The Event is created manually, but the rest is supposed to be "dynamic" (get or create)
Right now I'm trying to create a new car using my API, but I'm stuck. To get the cars event and session I'm trying to use the url;
/api/results/skrotbilsracet-29042016/r1/cars/
The idea is to post data to this url and "get or create" a new car object.
To get the correct session object for the new car session FK, I need to use a custom function that takes the kwargs and tries to find the session.
The more I read about how to solve this, the more confused I get.
Could someone push me in the right direction?
This is my latest attempt at solving this, which just gives me "{"session":["This field is required."]}"
models.py
class Session(models.Model):
session_types = (
('p', 'Practice'),
('q', 'Qualification'),
('r', 'Race')
)
event_id = models.ForeignKey(Event, related_name='sessions')
name = models.CharField(max_length=2, blank=True)
current_session = models.BooleanField(default=True)
session_type = models.CharField(max_length=2,
choices=session_types)
started = models.DateTimeField(auto_now_add=True)
ended = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['started']
def save(self):
if not self.name:
# Get number of sessions
session_count = Session.objects.filter(event_id=self.event_id)\
.filter(session_type=self.session_type)\
.count()
session_count += 1
self.name = self.session_type + str(session_count)
super(Session, self).save()
def __unicode__(self):
string = self.started.strftime("%d-%m-%Y %H:%M") + ' - '
string += self.name.upper()
return(string)
class Car(models.Model):
session = models.ForeignKey(Session, related_name='cars')
number = models.IntegerField()
full_name = models.CharField(max_length=256, blank=True)
short_name = models.CharField(max_length=256, blank=True)
race_class = models.CharField(max_length=50, blank=True)
best_lap = models.IntegerField(blank=True, null=True)
best_lap_time = models.CharField(max_length=20, blank=True)
best_sector1 = models.CharField(max_length=20, blank=True)
best_sector2 = models.CharField(max_length=20, blank=True)
best_sector3 = models.CharField(max_length=20, blank=True)
best_speed = models.IntegerField(blank=True, null=True)
pitstops = models.IntegerField(blank=True, null=True)
total_time = models.CharField(max_length=20, blank=True)
transponder = models.CharField(max_length=50, blank=True)
apiUrls.py
urlpatterns = [
url(r'^raceslug/$', raceSlugView.as_view(), name='race-slug'),
url(r'^events/$', eventsView.as_view(), name='event-list'),
url(r'^session/$', getSessionView.as_view(), name='session-pk'),
url(r'^(?P<event_id>[a-z0-9\-]+)/$', eventView.as_view(), name='event-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/$', sessionView.as_view(), name='session-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/cars/$', carsView.as_view(), name='car-list'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/(?P<number>[0-9]+)/$', carView.as_view(), name='car-detail'),
]
urlpatterns = format_suffix_patterns(urlpatterns)
api.py
class carsView(generics.ListCreateAPIView):
serializer_class = carSerializer
def get_session(self, event_id, name):
print('Getting session')
# Get event object
try:
event = Event.objects.get(event_id=event_id)
print('Found event')
except ObjectDoesNotExist:
print('Did not find event')
return
# Get session object
try:
session = event.sessions.get(name=name)
print('Found session: ', session)
return session
except ObjectDoesNotExist:
print('Did not find session')
return
def get_queryset(self):
print('Getting queryset')
print('event_id: ' + self.kwargs['event_id'])
print('name: ' + self.kwargs['name'])
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
return(Car.objects.filter(session=session.pk))
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
class Meta:
model = Car
fields = (
'session',
'number',
'full_name',
'short_name',
'race_class',
'best_lap',
'best_lap_time',
'best_sector1',
'best_sector2',
'best_sector3',
'best_speed',
'pitstops',
'total_time',
'transponder',
'laps')
Solution:
This is what I actually changed to get it working.
api.py
from rest_framework.serializers import ValidationError
class carsView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
number = self.request.POST.get('number')
car = session.cars.filter(number=number)
if car.exists():
raise ValidationError('Car already exists')
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
session = serializers.StringRelatedField(required=False)
...
I see that you're creating your session ID there:
def get_queryset(self):
...
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
return(Car.objects.filter(session=session.pk))
Then you don't need it in a serializer, only in a model. So you can set it a snot required in a serializer, but it will still be required in a model.
I guess this answer could help you: Django REST Framework serializer field required=false

Many-to-many relation on User table in Django

I'm writing an app where I need to associate data with user pairs. For instance, each user pair will have a compatibility score associated with them, as well as many-to-many relationships such as artists that they have in common. I'm confused about the best way to do this, it seems like I would use a combination of 1) extending User via the one-to-one relationship, 2) using a recursive relationship to self on the User table, 3) coupled with specifying extra fields on M2M relationships, but I can't wrap my head around what the model would look like.
This is how I am accomplishing this currently, which I assume is not the best way to do it as it requires two passes through the DB for each query:
in models.py (psuedo-code, assume there is an Artist class):
class UserProfile(models.Model):
user = models.OneToOneField(User)
zipcode = models.CharField(max_length=16)
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
class Score(models.Model):
user = models.ForeignKey(User, related_name='score_first_user')
second_user = models.ForeignKey(User, related_name='score_second_user')
dh_score = models.DecimalField(decimal_places=2, max_digits=5)
cre_date = models.DateTimeField(auto_now_add=True)
upd_date = models.DateTimeField(auto_now=True)
deleted = models.BooleanField()
class Meta:
unique_together = ('user', 'second_user')
class UserArtist(models.Model):
user = models.ForeignKey(User, related_name='userartist_first_user')
second_user = models.ForeignKey(User, related_name='userartist_second_user')
artist = models.ForeignKey(Artist)
cre_date = models.DateTimeField(auto_now_add=True)
upd_date = models.DateTimeField(auto_now=True)
deleted = models.BooleanField()
then in views.py I save scores and common artists using something like (pseudo-code):
s = Score(user=u, second_user=second_user score=dh_score)
s.save()
and retrieve them using something like:
u = User.objects.get(username="%s" % username)
user_scores = Score.objects.filter( Q(user=u.id) | Q(second_user=u.id) ).order_by('-dh_score')[:10]
for user_score in user_scores:
# non-relevant logic to determine who is user and who is partner
...
partner_artists = UserArtist.objects.filter( (Q(user=u.id) & Q(second_user=partner.id))\
| (Q(user=partner.id) & Q(second_user=u.id))
)
What is the best way to accomplish this?
Here is how I accomplished the user-to-user data pairing, as well as making a M2M relationship to the intermediate table:
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
pair = models.ManyToManyField('self', through='PairData', symmetrical=False)
def __unicode__(self):
return "%s's profile" % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
class PairData(models.Model):
first_user = models.ForeignKey(UserProfile, related_name='first_user')
second_user = models.ForeignKey(UserProfile, related_name='second_user')
raw_score = models.DecimalField(decimal_places=4, max_digits=9)
dh_score = models.DecimalField(decimal_places=2, max_digits=5)
distance = models.PositiveIntegerField()
cre_date = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return u"%s %s %f %d" % (self.first_user, self.second_user, self.dh_score, self.distance)
class Artist(models.Model):
pair = models.ManyToManyField(PairData)
artist_name = models.CharField(max_length=256)
def __unicode__(self):
return u"%s" % self.artist_name
Here is an example of how I queried the pair data (views.py):
def matches(request, username):
user_profile = User.objects.get(username=username).get_profile()
pd = PairData.objects.filter( Q(first_user=user_profile) | Q(second_user=user_profile) ).order_by('-dh_score')
and the artists associated with each pair:
def user_profile(request, username):
user_profile = User.objects.get(username=username).get_profile()
viewers_profile = request.user.get_profile()
pair = PairData.objects.filter( (Q(first_user=user_profile) & Q(second_user=viewers_profile)) \
| (Q(first_user=viewers_profile) & Q(second_user=user_profile)) )
artists = Artist.objects.filter(pair=pair)
If there is a better way to query without using Q, please share!