Django: Can you create a relationship with an auto-generated through table? - mysql

My code looks something like this:
from django.db import models
from django.conf import settings
User = settings.AUTH_USER_MODEL
class Dish(models.Model):
name = models.CharField(max_length=200)
class Meal(models.Model):
name = models.CharField(max_length=200)
dishes = models.ManyToManyField(Dish)
The many-to-many dishes field will result in a database table called 'myapp_meal_dishes' being created that includes id, meal_id, and dish_id fields.
I would like to add a MealDishEater model that connects with that auto-generated table:
class MealDishEater(models.Model):
meal_dish = models.ForeignKey(MealDishes, on_delete=models.CASCADE)
eater = models.ForeignKey(User, on_delete=models.PROTECT)
ate_meal = models.BooleanField(default=False)
Of course, that doesn't work, because MealDishes is not defined. Is there a way to do this or do I have to create my own through table?

You can access the ManyToManyField intermediate model with the through attribute. So this should work:
class MealDishEater(models.Model):
meal_dish = models.ForeignKey(Meal.dishes.through, on_delete=models.CASCADE)
Personally, though, I always create explicit through models for ManyToManyFields rather than allowing such magic.

Related

Unable to change the value of foreign key to foreign key of an object Django

I am having a model structure like:
class user(models.Model):
name = models.CharField(max_length=100)
tasks = models.IntegerField(default=0)
class project(models.Model):
worker = models.ForeignKey(user, on_delete=models.CASCADE)
project_name = models.CharField(max_length=100)
class task(models.Model):
project = models.ForeignKey(project, on_delete=models.CASCADE)
task_name = models.CharField(max_length=150)
expected_date = models.DateField(auto_now=False,auto_now_add=False,)
actual_date = models.DateField(auto_now=False,auto_now_add=False,blank=True,null=True,)
I want to traverse through the task list and if actual date field is not null i.e. task completed then to update the tasks field in user class by 1. I have written the following code:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
x.project.worker.tasks+=1
However this is not giving the desired result. What should I do?
You are not saving your object after modifying it - simply modifying the value doesn't write it to the database. Try this instead:
a = task.objects.filter(actual_date__isnull=False)
for x in a:
worker = x.project.worker
worker.tasks += 1
worker.save()
On a separate note you should consider following PEP8 conventions and using CamelCase for your class names. As it is currently you can very easily mix up classes with objects.

Django Query values_list getting last value

Lets say I have a blog and a class user in a model. Furthermore I have a class comment connected with a foreign key.
class User(models.Model):
UserName = models.CharField(max_length=50, blank=True)
UserCountry = models.CharField(max_length=2, blank=True)
class Comment(models.Model):
commentText = models.TextField(max_length=1000)
commentSub = models.ForeignKey(User, related_name='comLink')
created_at = models.DateTimeField(auto_now_add=True)
Now I want to make an csv export in model admin and a I have a queryset with values_list.
I am wondering whether there exists a possibility to get each User once and e.g. only the last comment?
myList = queryset.values_list('UserName', 'UserCountry', 'comLink__commentText')
comLink is the related name. Now I just want the last comment. A timestamp is existing and I have not figured out how to filter or reverse etc.
You can do it with Subquery, I don`t know your model design, so it would be approximately like that:
from django.db.models import OuterRef, Subquery
com = Comment.objects.filter(commentSub=OuterRef('pk')).order_by('-created_at')
myList = queryset.annotate(LastComment=Subquery(com.values('commentText')[:1]))
myList = myList.values_list('UserName', 'UserCountry', 'LastComment')
https://docs.djangoproject.com/en/2.0/ref/models/expressions/#subquery-expressions

Django Model: What is a efficient way to list Foreign Key?

I have three models below. I omit some irrelative fields.
class Team(models.Model):
name = models.CharField(max_length=100)
class Player(models.Model):
name = models.CharField(max_length=100)
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.CharField(max_length=100, null=True)
away_players = models.CharField(max_length=100, null=True)
home_players and away_players have the type of player id list, such as [1,2,3,...,15].
I want to know better ways like using Foreign Key List.
Because, I have some troubles in manually inserting players IDs at Django Admin Page. It takes much time finding player name in Player() and matching player's ID. I guess the task would be easier if I can assign a certain relationship between Player() and Team().
That would be a many-to-many relationship.
https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.ManyToManyField(Player)
away_players = models.ManyToManyField(Player)

Django REST - Resolving Foreign Keys and M2M's in a Serializer

I have the following Models:
class Player(models.Model):
name = models.CharField(max_length=30)
class Achievement(models.Model):
name = models.CharField(max_length=30)
class UnlockedAchievement(models.Model):
achievement = models.ForeignKey(Achievement)
date = models.DateTimeField()
class PlayerAchievements(models.Model):
player = models.ForeignKey(Player)
unlocked_achievements = models.ManyToManyField(UnlockedAchievement, related_name="unlocked_achievements", blank=True, null=True)
With a PUT, I'm trying to resolve both the Player's foreign key as well as the nested relationship of all the Achievements. My JSON data effectively looks like this:
{"name":"playername",
"achievements":
{
"ach1":"timestamp",
"ach2":"timestamp",
}
}
What I can't figure out is the magic combination of which kinds of Serializers to use and, when using them, which serializer fields or nested Serializers to use to be able to resolve Players by name, and the unlocked achievements (and then their Achievement foreign keys) by providing a name.
In this case I don't have access to id numbers, hence why things are done by names.
Such a strange mixture it seems. Can anyone lend a hand? Thanks in advance!
You can use nested relationships to fully include the serialization of a related model:
class AchievementSerializer(serializers.ModelSerializer):
class Meta:
model = Achievement
class UnlockedAchievementSerializer(serializers.ModelSerializer):
achievement = AchievementSerializer(many=False)
class Meta:
model = UnlockedAchievement
class PlayerAchievementsSerializer(serializers.ModelSerializer):
unlocked_achievements = UnlockedAchievementSerializer(many=True)
class Meta:
model = PlayerAchievements
class PlayerSerializer(serializers.ModelSerializer):
player_achievements = PlayerAchievementsSerializer(many=False)
class Meta:
model = Player
Then just filter the Player object by name and serialize it.

assign list elements to database entity in sqlalchemy from a list

I have a simple model as follows, i have a list of games and i want all the players to assign one and only one game, from the list of games. How would i do it in sqlalchemy.
As of now i am using flask sqlalchemy, but the question does not limit to flask-sqlalchemy.
games = ['soccer', 'hockey', 'baseball', 'cricket', 'basketball']
from flask.ext.sqlalchemy import SQLAlchemy
class Gamer(db.Model):
id = db.Column(db.Integer, primary_key=True)
team_name = db.Column(db.String(80))
game_name = db.Column(db.String(80))
game = db.Column(db.String(80), i want only games from the list of games)
The analogous django functionality is found here.
First of all, the django functionality you refer to is not really analogous to the model you list. The reason for this is that Gamer is a model whereas SimpleForm is a UI form.
However, below are few ways you can validate the model:
1) Create a separate tabbe for Games, add the values as rows, and create a N-to-1 relationship from Gamer to the Game. This is readable, and will validate your data on both the business and DB levels
class Game(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
class Gamer(db.Model):
# ...
game_id = db.Column(db.Integer, ForeignKey('game.id'))
game = relationship(Game)
2) Create and use a simple validator
from sqlalchemy.orm import validates
class Gamer(db.Model):
# ...
#validates('game')
def validate_game(self, key, address):
assert address in games
return address
edit-1: alternatively, take a look at the The Enum Recipe. But again this is on a model level, not UI validation.