I want to render category field on an article in terms of its name(choice). Currently, it is rendered as an Id. Also, I want to be able to update the article model by entering category name(choice) instead of its Id(I am currently doing this). How can I go about implementing this?
This is what I have so far.
Models
class Category(models.Model):
"""
Model for Category
"""
CATEGORY_CHOICES = (
('Sports', 'Sports'),
('Music', 'Music'),
('Drama', 'Drama'),
('Money', 'Money'),
('Movies', 'Movies'),
('Cars', 'Cars'),
('General', 'General'),
)
name = models.CharField(max_length=30, choices=CATEGORY_CHOICES, default='General',null=False, blank=True)
def __str__(self):
return self.name
class Article(models.Model):
"""
Model for an Article
"""
title = models.CharField(max_length=255, null=False, blank=False)
description = models.TextField(null=False, blank=False)
body = models.TextField(null=False, blank=False,)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
Serializers
class ArticleSerializer(serializers.ModelSerializer):
"""
Serializer for Article.
"""
class Meta:
model = Article
fields = ('title','description','body',''category')
class CategorySerializer(serializers.ModelSerializer):
"""
Serializer for Category.
"""
class Meta:
model = Category
fields = ('name',)
Current output
Expected output
You can change your ArticleSerializer to have the category field as a CharField with a source attribute:
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='category.name')
class Meta:
model = Article
fields = ('title','description','body',''category')
To be able to update the Article's category via the name, you have to make sure that name is a unique field for Category. If yes, then you can use a SlugRelatedField.
category = serializers.SlugRelatedField(slug_field='name')
Related
I am new to Django and would like to create a platform where teachers can create student profiles and assign reports to the specific student.
Therefore, I have made two models (Student & Report) and two CreateViews. When creating a report, the teacher has the option to select a student from a choice field. This I have done using ModelChoiceField. However, when submitting the report model, the students name is not saved to that model. How can I accomplish this?
Ultimately I would like to have a profile to each student showing their info and reports attached to their model.
models.py
class Student(models.Model):
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=30, default="")
age = models.CharField(max_length=2, default="", blank=True)
class Report(models.Model):
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
forms.py
class StudentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(StudentForm, self).__init__(*args, **kwargs)
class Meta:
model = Student
fields = ['name','age',]
class ReportForm(forms.ModelForm):
student = forms.ModelChoiceField(queryset=Student.name, initial=0)
class Meta:
model = Report
fields = ['title','file','player',]
views.py
class StudentCreate(LoginRequiredMixin, CreateView):
model = Student
template_name = 'student_create.html'
form_class = forms.StudentForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class ReportCreate(LoginRequiredMixin, CreateView):
model = Report
template_name = 'report_create.html'
form_class = forms.ReportForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Currently your Report model is like so:
class Report(models.Model):
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
The basic concept behind a model is that it is an abstraction / design of how we want the database table for some entity to look like. So the fields we add in a model are columns / attributes in our database table. If we want to store some data we need to have some column for it (or in terms of models a field).
Your model Report has no field for storing some student (in essence a foreign key to a Student, a foreign key is basically a pointer to a particular entry of another table). So you should add that to your model:
class Report(models.Model):
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=30)
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name="reports")
I have user serializer in which i need to show in every user detail advertises which he published
models.py:
class Advertise(models.Model):
title = models.CharField(max_length=120)
publisher = models.ForeignKey(User, related_name='publisher',null=True, blank=True, on_delete=models.CASCADE)
category = models.CharField(choices=CATEGORIES, max_length=120)
description = models.TextField(max_length= 200, null=True, blank=True)
image = models.ImageField(upload_to='project_static/Advertise/img', null=True, blank=False)
price = models.DecimalField(decimal_places=2, max_digits=20)
timestamp = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
location = models.CharField(max_length=120 , null=True, blank=True)
contact = models.CharField(max_length=120,null=True, blank=True)
def __str__(self):
"""show ad name in admin page"""
return self.title
def get_absolute_url(self):
return reverse("advertise:advertise-detail", kwargs={"pk":self.pk})
serilaizers.py:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.CharField(source='get_absolute_url')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher = AdSerializer(source='publisher_set', many=True)
class Meta:
model = User
fields = ['id', 'username','publisher']
error:
Got AttributeError when attempting to get a value for field publisher on serializer UserSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'publisher_set'.
ok, I solved it by making some changes:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.HyperlinkedIdentityField(view_name='advertise:ad_detailview', source='Advertise')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher_of = AdSerializer(many=True)
url = serializers.HyperlinkedIdentityField(view_name='advertise:user-detail', source='User')
class Meta:
model = User
fields = ('url', 'id','username', 'email', 'publisher_of')
also in models.py publisher field got related_name="publisher_of" for more symantic
This link helped
https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/
I am using Django 2.0
I have two models
class Chapter(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
name = models.CharField(max_length=250, blank=False)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class META:
verbose_name_plural = 'chapters'
db_table = 'chapters'
def __str__(self):
return self.name
class ChapterQuestion(models.Model):
chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE)
word = models.CharField(max_length=250)
definition = models.CharField(max_length=250)
class META:
verbose_name_plural = 'chapter questions'
db_table = 'chapter_questions'
def __str__(self):
return self.word
Since Each ChapterQuestion belongs to only one Chapter, I think it could be Many-to-one relation.
My admin.py contain only
admin.site.register(Chapter)
admin.site.register(ChapterQuestion)
I want to be able to add/edit multiple questions while creating/editing chapter using Django Admin.
But Django Admin is showing only chapter fields
Also, I want created_by column to be field automatically by logged in user and remove from form.
You need to use inline forms
class ChapterQuestionInline(admin.StackedInline):
model = ChapterQuestion
#admin.register(Chapter)
class ChapterAdmin(admin.ModelAdmin):
list_display = ["course","name","created_by"]
inlines = [ChapterQuestionInline]
I have a django model named Event, which references Customer model.
event_name = models.CharField(max_length=200, unique=True)
customer = models.ForeignKey(customer_models.Customer, db_index=True,
on_delete=models.SET_NULL,
related_name='customer_events', null=True)
event_location = models.CharField(max_length=200, default='')
event_date = models.DateField()
I need to get the customer list along with the latest event name for each user in the API.
Customer serializers.py file is
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
Customer views.py file is
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
How can I accomplish this?
In your Customer model you can have a property that returns the latest event name for a Customer instance:
class Customer(models.Model):
...
#property
def latest_event_name(self):
"""Return latest event name."""
# self.customer_events.order_by('event_date').last()
latest_event = self.customer_events.order_by('-event_date').first()
return latest_event.event_name if latest_event else None
In your serializer you can then add a ReadOnlyField for latest_event_name:
class CustomerSerializer(serializers.ModelSerializer):
latest_event_name = serializers.ReadOnlyField()
class Meta:
model = Customer
fields = '__all__'
I have two models Company and Campaign. I need to create a relationship between them. I think my models are fine.
companies/model.py
class Company(models.Model):
class Meta:
verbose_name_plural = "companies"
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(blank=False, max_length=128, default='')
slug = models.SlugField(blank=True, unique=True)
archived = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
campaigns/models.py
class Campaign(models.Model):
class Meta:
verbose_name_plural = "campaigns"
company = models.ForeignKey('companies.Company', on_delete=models.CASCADE,)
title = models.CharField(blank=False, max_length=128, default='')
slug = models.UUIDField(default=uuid.uuid4, blank=True, editable=False)
def __str__(self):
return str(self.title)
campaigns/forms.py
class CampaignForm(forms.ModelForm):
class Meta:
model = Campaign
fields = ['title','description','archived']
campaigns/views.py
class CampaignCreateView(SubmitBtnMixin, CreateView):
model = Campaign
company = None
form_class = CampaignForm
submit_btn = "Add Campaign"
template_name = "form.html"
campaigns/urls.py
url(r'^campaign/create/$', CampaignCreateView.as_view(), name='campaign-create'),
My question is, when creating a new campaign, where and how do I pick up the Company pk to populate the Campaign model? What is the most secure and best practice for doing this?
I found a solution but would like input on best practices still.
I added this to my CampaignCreateView
def form_valid(self, form):
company = get_object_or_404(Company, id=self.kwargs.get('pk'), user_id=self.request.user.id)
form.instance.company_id = company.id
return super(CampaignCreateView, self).form_valid(form)
and I changed my url to:
url(r'^campaign/(?P<pk>\d+)/create/$', CampaignCreateView.as_view()...
Not sure that I like the pk in the URL since it can be jacked. This is why I am filtering on the userid at the company model to make sure that the data is coming from the owner.
I thought of doing this by registering the company in the session id but I am not convinced that sessions do not present their own problems.