网站建设意识形态今日头条军事新闻
本练习重点要掌握的地方
1. 根据项目描述,定义数据模型,数据模型的设计有原则,要符合数据库的三范式,要尽可能的解耦。
2. 熟悉表的外键关联
3. ORM框架
4. 根据业务需求,在Django框架中添加索引,以及唯一约束。
5. 借助Django框架编写单元测试,调试定义的模型。
LintCode 2427 实现推文模型
根据描述定义字段,只有三个字段,其中user字段是外键,使用Django框架定义好的,content是text,创建时间是日期类型,使用自动添加模版。
from django.db import models
from django.contrib.auth.models import Userclass Tweet(models.Model):# write your code hereuser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)content = models.CharField(max_length=140)created_at = models.DateTimeField(auto_now_add=True)def __str__(self):return f'{self.created_at} {self.user}: {self.content}'
让我们来过一遍一下单元测试:
from django.contrib.auth.models import User
from django.test import TestCase
from tweets.models import Tweet
from datetime import date
import reclass TweetTests(TestCase):def test_tweet_model_attributes(self):self.assertEqual(hasattr(Tweet, 'user'), True)self.assertEqual(hasattr(Tweet, 'content'), True)self.assertEqual(hasattr(Tweet, 'created_at'), True)def test_tweet_model(self):user = User.objects.create(username='linghu', password='god')tweet = Tweet.objects.create(content='jiuzhangdafahao')self.assertEqual(tweet.user, None)self.assertEqual(tweet.created_at.day, date.today().day)tweet.delete()Tweet.objects.create(user=user, content='jiuzhangdafahao')user.delete()self.assertEqual(Tweet.objects.all().count(), 1)self.assertEqual(Tweet.objects.first().user, None)self.assertEqual(Tweet.content.field.max_length, 140)def test_auto_now_add(self):tweet: Tweet = Tweet.objects.create(content='jiuzhangdafahao')old_created_time = tweet.created_attweet.content = 'updated tweet'tweet.save()self.assertEqual(old_created_time, tweet.created_at)def test_str(self):user = User.objects.create(username='linghu', password='god')tweet: Tweet = Tweet.objects.create(user=user, content='jiuzhangdafahao')self.assertEqual(str(tweet.created_at) in str(tweet), True)self.assertEqual(tweet.user.username in str(tweet), True)self.assertEqual(tweet.content in str(tweet), True)
查看tweet发了多久
from django.db import models
from django.contrib.auth.models import User
from utils.time_helpers import utc_now
from datetime import datetimeclass Tweet(models.Model):user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)content = models.CharField(max_length=140)created_at = models.DateTimeField(auto_now_add=True)@propertydef hours_to_now(self):return (utc_now() - self.created_at).seconds // 3600
2434 · 定义联合索引和默认的排序规则
为tweet添加索引,先按用户id排序,然后再按创建时间降序排序
from django.db import models
from django.contrib.auth.models import Userclass Tweet(models.Model):user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)content = models.CharField(max_length=140)created_at = models.DateTimeField(auto_now_add=True)# write your code hereclass Meta:index_together = ('user', 'created_at')ordering = ('user', '-created_at')
同样看一下如何测试排序
from django.test import TestCase
from tweets.models import Tweet
from datetime import datetime, timezone
import randomclass TweetTests(TestCase):def test_tweet_meta(self):self.assertEqual(len(Tweet._meta.index_together), 1)self.assertEqual(Tweet._meta.index_together[0], ('user', 'created_at'))self.assertEqual(Tweet._meta.ordering, ('user', '-created_at'))def test_tweet_ordering(self):for i in range(10):Tweet.objects.create(content='default tweet content')tweets = Tweet.objects.all()for index in range(len(tweets)-1):self.assertEqual(tweets[index].created_at > tweets[index+1].created_at, True)random_tweet: Tweet = tweets[random.randint(0, len(tweets)-1)]random_tweet.created_at = datetime(random.randint(2000, 2020), 6, 1, 0, 0, 0).replace(tzinfo=timezone.utc)random_tweet.save()tweets = Tweet.objects.all()for index in range(len(tweets)-1):self.assertEqual(tweets[index].created_at > tweets[index+1].created_at, True)
定义评论模型
评论user和tweet作为外键,索引先按tweet排序,再按create_at排序
from django.db import models
from django.contrib.auth.models import User
from tweets.models import Tweetclass Comment(models.Model):# write your code hereuser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)tweet = models.ForeignKey(Tweet, on_delete=models.SET_NULL, null=True)content = models.CharField(max_length=140)created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)# write your code hereclass Meta:index_together = ('tweet', 'created_at')def __str__(self):return f"{self.created_at} - {self.user} says {self.content} at tweet {self.tweet_id}"
2430 · 实现好友关系模型
这个除了索引以外,还需要有一个唯一约束,即不能关注同一个人两次。
from django.db import models
from django.contrib.auth.models import Userclass Friendship(models.Model):# write your code herefrom_user = models.ForeignKey(User,on_delete=models.SET_NULL,null=True,related_name='following_friendship_set',)to_user = models.ForeignKey(User,on_delete=models.SET_NULL,null=True,related_name='follower_friendship_set',)created_at = models.DateTimeField(auto_now_add=True)class Meta:index_together = (('from_user_id', 'created_at'),('to_user_id', 'created_at'),)unique_together = (('from_user_id', 'to_user_id'),)def __str__(self):return f'{self.from_user_id} followed {self.to_user_id}'
定义新鲜事模型
from django.db import models
from django.contrib.auth.models import User
from tweets.models import Tweetclass NewsFeed(models.Model):# write your code hereuser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)tweet = models.ForeignKey(Tweet, on_delete=models.SET_NULL, null=True)created_at = models.DateTimeField(auto_now_add=True)class Meta:index_together = ('user','created_at')unique_together = ('user', 'tweet')ordering = ('user', '-created_at')def __str__(self):return f"{self.created_at} inbox of {self.user}: {self.tweet}"
定义点赞模型
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import modelsclass Like(models.Model):# write your code herecontent_type = models.ForeignKey(ContentType,on_delete=models.SET_NULL,null=True,)object_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)created_at = models.DateTimeField(auto_now_add=True)# write your code hereclass Meta:index_together = ('content_type', 'object_id', 'created_at')unique_together = ('content_type', 'object_id', 'user')def __str__(self):return f"{self.created_at} - {self.user} liked {self.content_type} {self.object_id}"