Answer the question
In order to leave comments, you need to log in
How to write CreateView for model with ForeignKey?
Hello, please help a newbie - there is such a model: countries and cities within countries, each city is a Foreign Key for a specific country. It's very easy to create a CreateView for a country, no questions, but I can't create a CreateView for a city - Foreign Key interferes. There are no examples in the documentation - there is only a vague example about the author's foreign key. form.instance.created_by = self.request.user
This example does not help in this case. How to be?
models.py
class Countries(models.Model):
....
country_name=models.CharField(max_length=30, choices=COUNTRY_CHOICE)
....
class Cities(models.Model):
country=models.ForeignKey(Countries, on_delete=models.CASCADE)
city_name=models.CharField(max_length=100)
....
path('countries/<int: country_id>/new_city/', login_required(CityCreate.as_view()), name='new_city')
class CityCreate(CreateView):
model=Cities
fields=['city_name', 'tags']
success_url=reverse_lazy('countries:cities')
template_name='countries/new_city.html'
def get(self, request, *args, **kwargs):
self.country=Countries.objects.get(id=self.kwargs['country_id'])
return super(CityCreate, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context=super(CityCreate, self).get_context_data(**kwargs)
context['country']=self.country
return context
def form_valid(self, form):
form.instance.country=self.country
return super().form_valid(form)
country: {{ country }}
<form action="{% url 'countries:new_city' country.id %}" method='post' class="form">
{% csrf_token %}
</form>
Answer the question
In order to leave comments, you need to log in
In general, here is the code that works (other approaches did not help):
class CityCreate(CreateView):
model = Cities
fields = ['city_name', 'tags']
template_name = 'countries/new_city.html'
def get_success_url(self):
return reverse('countries:cities', args=[self.country.id])
def get_context_data(self, **kwargs):
self.country = get_object_or_404(Countries, id=self.kwargs['country_id'])
kwargs['country'] = self.country
return super().get_context_data(**kwargs)
def form_valid(self, form):
self.country = get_object_or_404(Countries, id=self.kwargs['country_id'])
form.instance.country = self.country
messages.success(self.request, 'The city has been added to the list of visited places, thank you')
return super().form_valid(form)
First, please follow PEP-8 and Django Coding Style. This is respect for those who have to read your code. Also, note that models are usually referred to in the singular: City, not Cities. Country, not Countries.
Secondly, with this use of CreateView, the form is automatically created. You also need your own form that will assign the country. Create a form for City, in the constructor of which the Country from the request will be stored. And in CreateView, instead of the fields attribute, use form_class to use your form.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question